package com.mosty.base.utils;

import com.mosty.common.base.exception.BusinessException;
import com.mosty.common.base.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @author zhangzhao
 * @description 时间扩展工具类
 * @modifier zhangzhao
 * @modifiedTime 2023/10/27 9:43
 * @since 2023/10/27 9:43
 */
@Slf4j
public class DatePlusUtils {

    /**
     * 数量-每天的小时数
     */
    public static final int RADIX_HOUR_IN_DAY = 24;

    /**
     * 数量-每小时分钟数
     */
    public static final int RADIX_MINUTE_IN_HOUR = 60;

    /**
     * 数量-每分钟秒数
     */
    public static final int RADIX_SECOND_IN_MINUTE = 60;

    /**
     * 数量-每秒毫秒数
     */
    public static final int RADIX_MILLISECOND_IN_SECOND = 1000;

    /**
     * 数量-每天毫秒数（1000 * 60 * 60 * 24）
     */
    public static final int RADIX_MILLISECOND_IN_DAY = RADIX_MILLISECOND_IN_SECOND * RADIX_SECOND_IN_MINUTE * RADIX_MINUTE_IN_HOUR * RADIX_HOUR_IN_DAY;

    /**
     * 数量-每小时毫秒数（1000 * 60 * 60）
     */
    public static final int RADIX_MILLISECOND_IN_HOUR = RADIX_MILLISECOND_IN_SECOND * RADIX_SECOND_IN_MINUTE * RADIX_MINUTE_IN_HOUR;

    /**
     * 数量-每分钟毫秒数（1000 * 60）
     */
    public static final int RADIX_MILLISECOND_IN_MINUTE = RADIX_MILLISECOND_IN_SECOND * RADIX_SECOND_IN_MINUTE;

    /**
     * 每年开始日期
     */
    public static final String YEAR_START_DATE = "-01-01";

    /**
     * 每年结束日期
     */
    public static final String YEAR_END_DATE = "-12-31";

    /**
     * 每月开始日期
     */
    public static final String MONTH_START_DATE = "-01";

    /**
     * 每日开始时间
     */
    public static final String DAY_START_TIME = " 00:00:00";

    /**
     * 每日结束时间
     */
    public static final String DAY_END_TIME = " 23:59:59";

    /**
     * 小时开始时间
     */
    public static final String HOUR_START_TIME = ":00:00";

    /**
     * 小时结束时间
     */
    public static final String HOUR_END_TIME = ":59:59";

    /**
     * 下一日期参数-年数
     */
    public static final String NEXT_TYPE_YEAR = "Y";

    /**
     * 下一日期参数-月数
     */
    public static final String NEXT_TYPE_MONTH = "M";

    /**
     * 下一日期参数-天数
     */
    public static final String NEXT_TYPE_DAY = "D";

    /**
     * 下一日期参数-小时数
     */
    public static final String NEXT_TYPE_HOUR = "H";

    /**
     * 下一日期参数-分钟数
     */
    public static final String NEXT_TYPE_MINUTE = "m";

    /**
     * 下一日期参数-秒数
     */
    public static final String NEXT_TYPE_SECOND = "S";

    /**
     * 中文星期数组
     */
    public static String[] CHINESE_WEEKS_ARRAY = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};

    //-------------------------时间格式字符串-------------------------//

    /**
     * 时间格式字符串-年份
     */
    public static final String FORMAT_YEAR = "yyyy";

    /**
     * 时间格式字符串-年份月份
     */
    public static final String FORMAT_YEAR_MONTH = "yyyy-MM";

    /**
     * 时间格式字符串-月份天数
     */
    public static final String FORMAT_MONTH_DAY = "MM-dd";

    /**
     * 时间格式字符串-日期
     */
    public static final String FORMAT_DATE = "yyyy-MM-dd";

    /**
     * 时间格式字符串-日期时间
     */
    public static final String FORMAT_DATE_TIME = "yyyy-MM-dd HH:mm:ss";

    /**
     * 时间格式字符串-日期小时
     */
    public static final String FORMAT_DATE_HOUR = "yyyy-MM-dd HH";

    /**
     * 时间格式字符串-日期分钟
     */
    public static final String FORMAT_DATE_MINUTE = "yyyy-MM-dd HH:mm";

    /**
     * 时间格式字符串-时间
     */
    public static final String FORMAT_TIME = "HH:mm:ss";

    /**
     * 时间格式字符串-分钟
     */
    public static final String FORMAT_MINUTE = "HH:mm";

    /**
     * 时间格式字符串-月份
     */
    public static final String FORMAT_MONTH = "MM";

    /**
     * 时间格式字符串-天数
     */
    public static final String FORMAT_DAY = "dd";

    /**
     * 时间格式字符串-小时
     */
    public static final String FORMAT_HOUR = "HH";

    /**
     * 时间格式字符串-日期-无间隔
     */
    public static final String FORMAT_DATE_COMPACT = "yyyyMMdd";

    /**
     * 时间格式字符串-日期时间-无间隔
     */
    public static final String FORMAT_DATE_TIME_COMPACT = "yyyyMMddHHmmss";

    /**
     * 时间格式字符串-日期小时-无间隔
     */
    public static final String FORMAT_DATE_HOUR_COMPACT = "yyyyMMddHH";

    /**
     * 时间格式字符串-日期分钟-无间隔
     */
    public static final String FORMAT_DATE_MINUTE_COMPACT = "yyyyMMddHHmm";

    /**
     * 时间格式字符串-日期时间戳-无间隔
     */
    public static final String FORMAT_DATE_TIME_STAMP_COMPACT = "yyyyMMddHHmmssSSS";

    /**
     * 时间格式字符串-月份天数-无间隔
     */
    public static final String FORMAT_MONTH_DAY_COMPACT = "MMdd";

    //--------------------------时间格式化--------------------------//

    /**
     * 时间格式化-年份（yyyy）
     */
    public static final SimpleDateFormat FORMATTER_YEAR = new SimpleDateFormat(DatePlusUtils.FORMAT_YEAR);

    /**
     * 时间格式化-年份月份（yyyy-MM）
     */
    public static final SimpleDateFormat FORMATTER_YEAR_MONTH = new SimpleDateFormat(DatePlusUtils.FORMAT_YEAR_MONTH);

    /**
     * 时间格式化-月份天数（MM-dd）
     */
    public static final SimpleDateFormat FORMATTER_MONTH_DAY = new SimpleDateFormat(DatePlusUtils.FORMAT_MONTH_DAY);

    /**
     * 时间格式化-日期（yyyy-MM-dd）
     */
    public static final SimpleDateFormat FORMATTER_DATE = new SimpleDateFormat(DatePlusUtils.FORMAT_DATE);

    /**
     * 时间格式化-日期时间（yyyy-MM-dd HH:mm:ss）
     */
    public static final SimpleDateFormat FORMATTER_DATE_TIME = new SimpleDateFormat(DatePlusUtils.FORMAT_DATE_TIME);

    /**
     * 时间格式化-日期小时（yyyy-MM-dd HH）
     */
    public static final SimpleDateFormat FORMATTER_DATE_HOUR = new SimpleDateFormat(DatePlusUtils.FORMAT_DATE_HOUR);

    /**
     * 时间格式化-日期分钟（yyyy-MM-dd HH:mm）
     */
    public static final SimpleDateFormat FORMATTER_DATE_MINUTE = new SimpleDateFormat(DatePlusUtils.FORMAT_DATE_MINUTE);

    /**
     * 时间格式化-时间（HH:mm:ss）
     */
    public static final SimpleDateFormat FORMATTER_TIME = new SimpleDateFormat(DatePlusUtils.FORMAT_TIME);

    /**
     * 时间格式化-分钟（HH:mm）
     */
    public static final SimpleDateFormat FORMATTER_MINUTE = new SimpleDateFormat(DatePlusUtils.FORMAT_MINUTE);

    /**
     * 时间格式化-月份（MM）
     */
    public static final SimpleDateFormat FORMATTER_MONTH = new SimpleDateFormat(DatePlusUtils.FORMAT_MONTH);

    /**
     * 时间格式化-天数（dd）
     */
    public static final SimpleDateFormat FORMATTER_DAY = new SimpleDateFormat(DatePlusUtils.FORMAT_DAY);

    /**
     * 时间格式化-小时（HH）
     */
    public static final SimpleDateFormat FORMATTER_HOUR = new SimpleDateFormat(DatePlusUtils.FORMAT_HOUR);

    /**
     * 时间格式化-日期时间-无间隔（yyyyMMdd）
     */
    public static final SimpleDateFormat FORMATTER_DATE_COMPACT = new SimpleDateFormat(DatePlusUtils.FORMAT_DATE_COMPACT);

    /**
     * 时间格式化-日期时间-无间隔（yyyyMMddHHmmss）
     */
    public static final SimpleDateFormat FORMATTER_DATE_TIME_COMPACT = new SimpleDateFormat(DatePlusUtils.FORMAT_DATE_TIME_COMPACT);

    /**
     * 时间格式化-日期小时-无间隔（yyyyMMddHH）
     */
    public static final SimpleDateFormat FORMATTER_DATE_HOUR_COMPACT = new SimpleDateFormat(DatePlusUtils.FORMAT_DATE_HOUR_COMPACT);

    /**
     * 时间格式化-日期分钟-无间隔（yyyyMMddHHmm）
     */
    public static final SimpleDateFormat FORMATTER_DATE_MINUTE_COMPACT = new SimpleDateFormat(DatePlusUtils.FORMAT_DATE_MINUTE_COMPACT);

    /**
     * 时间格式化-日期时间戳-无间隔（yyyyMMddHHmmssSSS）
     */
    public static final SimpleDateFormat FORMATTER_DATE_TIME_STAMP_COMPACT = new SimpleDateFormat(DatePlusUtils.FORMAT_DATE_TIME_STAMP_COMPACT);

    /**
     * 时间格式化-月份天数-无间隔（MMdd）
     */
    public static final SimpleDateFormat FORMATTER_MONTH_DAY_COMPACT = new SimpleDateFormat(DatePlusUtils.FORMAT_MONTH_DAY_COMPACT);

    /**
     * 取得系统当前的年份，格式如: (2008)
     * @return String
     */
    public static String getSystemYearString() {
        return DatePlusUtils.FORMATTER_YEAR.format(new Date());
    }

    /**
     * 取得系统当前的年份，格式如: (2008-05)
     * @return String
     */
    public static String getSystemYearMonthString() {
        return DatePlusUtils.FORMATTER_YEAR_MONTH.format(new Date());
    }

    /**
     * 取得系统当前的日期字符表达式，格式如: (2008-05-12)
     * @return String
     */
    public static String getSystemDateString() {
        return DatePlusUtils.FORMATTER_DATE.format(new Date());
    }

    /**
     * 取得系统当前的日期时间字符表达式，格式如: (2008-05-12 14:28:36)<br>
     * @return String
     */
    public static String getSystemDateTimeString() {
        return DatePlusUtils.FORMATTER_DATE_TIME.format(new Date());
    }

    /**
     * 取得系统当前的日期时间字符表达式，格式如: (20080512142836)<br>
     * @return String
     */
    public static String getSystemDateTimeCompactString() {
        return DatePlusUtils.FORMATTER_DATE_TIME_COMPACT.format(new Date());
    }

    /**
     * 取得系统当前的日期时间错字符表达式(带毫秒数)，格式如: (20080512142836326)<br>
     * @return String
     */
    public static String getSystemDateTimeStampCompactString() {
        return DatePlusUtils.FORMATTER_DATE_TIME_STAMP_COMPACT.format(new Date());
    }

    /**
     * 取得一个日期的字符表达式，格式如: (2008)
     * @param convertDate 需要转换的日期
     * @return String
     */
    public static String getYearString(Date convertDate){
        if(convertDate == null){
            return "";
        }
        return DatePlusUtils.FORMATTER_YEAR.format(convertDate);
    }

    /**
     * 取得一个日期的字符表达式，格式如: (12)
     * @param convertDate 需要转换的日期
     * @return String
     */
    public static String getDayString(Date convertDate){
        if(convertDate == null){
            return "";
        }
        return DatePlusUtils.FORMATTER_DAY.format(convertDate);
    }

    /**
     * 取得一个日期的字符表达式，格式如: (05)
     * @param convertDate 需要转换的日期
     * @return String
     */
    public static String getHourString(Date convertDate){
        if(convertDate == null){
            return "";
        }
        return DatePlusUtils.FORMATTER_HOUR.format(convertDate);
    }

    /**
     * 取得一个日期的字符表达式，格式如: (2008-05-12)
     * @param convertDate 需要转换的日期
     * @return String
     */
    public static String getDateString(Date convertDate) {
        if(convertDate == null){
            return "";
        }
        return DatePlusUtils.FORMATTER_DATE.format(convertDate);
    }

    /**
     * 获取每天的开始日期时间，格式如: (2008-05-12)（不传日期则计算当前日期）
     * @param convertDate 日期
     * @return Date
     */
    public static Date getDateBeginReturnDate(Date convertDate){
        if(convertDate == null){
            convertDate = new Date();
        }
        String dateString = DatePlusUtils.getDateString(convertDate);
        return DatePlusUtils.stringToDate(dateString, DatePlusUtils.FORMAT_DATE);
    }

    /**
     * 获取每天的开始日期时间，格式如: (2008-05-12 23:59:59)（不传日期则计算当前日期）
     * @param convertDate 日期
     * @return Date
     */
    public static Date getDateEndReturnDate(Date convertDate){
        if(convertDate == null){
            convertDate = new Date();
        }
        String dateString = DatePlusUtils.getDateString(convertDate) + DatePlusUtils.DAY_END_TIME;
        return DatePlusUtils.stringToDate(dateString, DatePlusUtils.FORMAT_DATE_TIME);
    }

    /**
     * 取得一个日期小时的字符表达式，格式如: (2008-05-12 02)<br>
     * @param convertDate 需要转换的日期
     * @return String
     */
    public static String getDateHourString(Date convertDate) {
        if(convertDate == null){
            return "";
        }
        return DatePlusUtils.FORMATTER_DATE_HOUR.format(convertDate);
    }

    /**
     * 取得一个日期时间的字符表达式，格式如: (2008-05-12 14:28:36)<br>
     *
     * @param convertDate 需要转换的日期
     * @return String
     */
    public static String getDateTimeString(Date convertDate) {
        if(convertDate == null){
            return "";
        }
        return DatePlusUtils.FORMATTER_DATE_TIME.format(convertDate);
    }

    /**
     * 取得一个时间的字符表达式，格式如: (14:28:36)<br>
     *
     * @param convertDate 需要转换的日期
     * @return String
     */
    public static String getTimeString(Date convertDate) {
        if(convertDate == null){
            return "";
        }
        return DatePlusUtils.FORMATTER_TIME.format(convertDate);
    }

    /**
     * 取得一个日期的紧凑字符表达式，格式如: (20080512)<br>
     * @param convertDate 需要转换的日期
     * @return String
     */
    public static String getDateCompactString(Date convertDate) {
        if(convertDate == null){
            return "";
        }
        return DatePlusUtils.FORMATTER_DATE_COMPACT.format(convertDate);
    }

    /**
     * 取得一个日期时间的紧凑字符表达式，格式如: (20080512142836)<br>
     * @param convertDate 需要转换的日期
     * @return String
     */
    public static String getDateTimeCompactString(Date convertDate) {
        if(convertDate == null){
            return "";
        }
        return DatePlusUtils.FORMATTER_DATE_TIME_COMPACT.format(convertDate);
    }

    /**
     * 取得一个日期的中文字符表达式，格式如: (2008年5月12日)<br>
     * @param convertDate 需要转换的日期
     * @return String
     */
    public static String getChineseDateString(Date convertDate) {
        if(convertDate == null){
            return "";
        }
        return DateFormat.getDateInstance(DateFormat.LONG).format(convertDate);
    }

    /**
     * 取得一个日期的中文字符表达式，使用字符串拼接的方式，格式如: (2008年5月12日)<br>
     * @param convertDate 需要转换的日期
     * @return String
     */
    public static String getChineseDateStringByMontage(Date convertDate) {
        String returnValue = "";
        if (convertDate != null) {
            String temp = DatePlusUtils.FORMATTER_DATE_COMPACT.format(convertDate);
            returnValue = temp.substring(0, 4) + "年";
            if("0".equals(temp.substring(4, 5))){
                returnValue += temp.substring(5, 6);
            }else{
                returnValue += temp.substring(4, 6);
            }
            returnValue += "月" + temp.substring(6, 8) + "日";
        }
        return returnValue;
    }

    /**
     * 取得一个日期时间的中文字符表达式，格式如: (2008年05月12日14时)<br>
     *
     * @param convertDate 需要转换的日期
     * @return String
     */
    public static String getChineseDateHourString(Date convertDate) {
        String returnValue = "";
        if (convertDate != null) {
            String temp = DatePlusUtils.FORMATTER_DATE_HOUR_COMPACT.format(convertDate);
            returnValue = temp.substring(0, 4) + "年" + temp.substring(4, 6)
                    + "月" + temp.substring(6, 8) + "日" + temp.substring(8, 10)
                    + "时";
        }
        return returnValue;
    }

    /**
     * 取得一个日期时间的中文字符表达式，格式如: (2008年05月12日14时28分)<br>
     * @param convertDate 需要转换的日期
     * @return String
     */
    public static String getChineseDateTimeString(Date convertDate) {
        String returnValue = "";
        if (convertDate != null) {
            String temp = DatePlusUtils.FORMATTER_DATE_TIME_COMPACT.format(convertDate);
            returnValue = temp.substring(0, 4) + "年" + temp.substring(4, 6)
                    + "月" + temp.substring(6, 8) + "日" + temp.substring(8, 10)
                    + "时" + temp.substring(10, 12) + "分";
        }
        return returnValue;
    }

    /**
     * 取得一个日期的中文字符表达式，包括星期，格式如: (2008年5月12日 星期一)<br>
     * @param convertDate 需要转换的日期
     * @return String
     */
    public static String getChineseDateWeekString(Date convertDate) {
        String returnValue = "";
        if (convertDate != null) {
            DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.FULL);
            returnValue = dateFormat.format(convertDate);
        }
        return returnValue;
    }

    /**
     * 取得一个日期星期的中文字符表达式，格式如: (星期一)<br>
     * @param convertDate 需要转换的日期
     * @return String
     */
    public static String getChineseWeekString(Date convertDate){
        String returnValue = "";
        if (convertDate != null) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(convertDate);
            int weekIndex = cal.get(Calendar.DAY_OF_WEEK) - 1;
            if(weekIndex < 0){
                weekIndex = 0;
            }
            returnValue = CHINESE_WEEKS_ARRAY[weekIndex];
        }
        return returnValue;
    }

    /**
     * 取得一个日期的纯中文字符表达式，格式如: (2008-05-12 转换后得到 二00八年五月十二日)<br>
     * @param dateString 需要转换的日期字符串
     * @return String
     */
    public static String getPureChineseDateString(String dateString) throws Exception {
        if (StringUtils.isBlank(dateString)) {
            return "";
        }
        StringBuilder returnValue = new StringBuilder();
        String[] chinaNumber = new String[10];
        chinaNumber[0] = "0";
        chinaNumber[1] = "一";
        chinaNumber[2] = "二";
        chinaNumber[3] = "三";
        chinaNumber[4] = "四";
        chinaNumber[5] = "五";
        chinaNumber[6] = "六";
        chinaNumber[7] = "七";
        chinaNumber[8] = "八";
        chinaNumber[9] = "九";
        String tempString = "";
        try {
            tempString = dateString.substring(0, 4);
            for (int i = 0; i < tempString.length(); i++) {
                int cn = Integer.parseInt(tempString.substring(i, i + 1));
                returnValue.append(chinaNumber[cn]);
            }
            returnValue.append("年");
            tempString = dateString.substring(5, 7);
            for (int i = 0; i < tempString.length(); i++) {
                int cn = Integer.parseInt(tempString.substring(i, i + 1));
                if (i == 0) {
                    if (cn == 1) {
                        returnValue.append("十");
                    }
                } else {
                    if (cn > 0){
                        returnValue.append(chinaNumber[cn]);
                    }
                }
            }
            returnValue.append("月");
            tempString = dateString.substring(8);
            for (int i = 0; i < tempString.length(); i++) {
                int cn = Integer.parseInt(tempString.substring(i, i + 1));
                if (i == 0) {
                    switch (cn) {
                        case 0:
                            break;
                        case 1:
                            returnValue.append("十");
                            break;
                        default:
                            returnValue.append(chinaNumber[cn]).append("十");
                            break;
                    }
                } else {
                    if (cn > 0) {
                        returnValue.append(chinaNumber[cn]);
                    }
                }
            }
            returnValue.append("日");
            return returnValue.toString();
        } catch (Exception ex) {
            log.error("日期转换错误: 转换字符串: " + dateString + "，" + ex.getMessage(), ex);
            throw new Exception("日期转换错误: 转换字符串: " + dateString + "，" + ex.getMessage());
        }
    }

    /**
     * 取得一个日期的纯中文字符表达式，格式如: (2008-05-12 转换后得到 二○○八年五月十二日)<br>
     * @param dateString 需要转换的日期字符串
     * @return String
     */
    public static String getPureChineseDateString2(String dateString) throws Exception {
        if (StringUtils.isBlank(dateString)) {
            return "";
        }
        StringBuilder returnValue = new StringBuilder();
        String[] chinaNumber = new String[10];
        chinaNumber[0] = "○";
        chinaNumber[1] = "一";
        chinaNumber[2] = "二";
        chinaNumber[3] = "三";
        chinaNumber[4] = "四";
        chinaNumber[5] = "五";
        chinaNumber[6] = "六";
        chinaNumber[7] = "七";
        chinaNumber[8] = "八";
        chinaNumber[9] = "九";
        String tempString = "";
        try {
            tempString = dateString.substring(0, 4);
            for (int i = 0; i < tempString.length(); i++) {
                int cn = Integer.parseInt(tempString.substring(i, i + 1));
                returnValue.append(chinaNumber[cn]);
            }
            returnValue.append("年");
            tempString = dateString.substring(5, 7);
            for (int i = 0; i < tempString.length(); i++) {
                int cn = Integer.parseInt(tempString.substring(i, i + 1));
                if (i == 0) {
                    if (cn == 1) {
                        returnValue.append("十");
                    }
                } else {
                    if (cn > 0) {
                        returnValue.append(chinaNumber[cn]);
                    }
                }
            }
            returnValue.append("月");
            tempString = dateString.substring(8);
            for (int i = 0; i < tempString.length(); i++) {
                int cn = Integer.parseInt(tempString.substring(i, i + 1));
                if (i == 0) {
                    switch (cn) {
                        case 0:
                            break;
                        case 1:
                            returnValue.append("十");
                            break;
                        default:
                            returnValue.append(chinaNumber[cn]).append("十");
                            break;
                    }
                } else {
                    if (cn > 0) {
                        returnValue.append(chinaNumber[cn]);
                    }
                }
            }
            returnValue.append("日");
            return returnValue.toString();
        } catch (Exception ex) {
            log.error("日期转换错误: 转换字符串: " + dateString + "," + ex.getMessage(), ex);
            throw new Exception("日期转换错误: 转换字符串: " + dateString + "," + ex.getMessage());
        }
    }

    /**
     * 取得指定的下一个日期
     * 注意：按月运算时，如果运算后当月没有该日，则为当月的最后一天
     * @param startDate 开始日期
     * @param nextType  运算类型（Y=年数；M=月数；D=天数；H=小时数；m=分钟数；S=秒数）
     * @param nextStep  运算长度（为负数指取以前的日期）
     * @return java.util.Date
     */
    public static Date getNextDate(Date startDate, String nextType, int nextStep) {
        Date endDate = startDate;
        if (startDate != null) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(startDate);
            switch (nextType) {
                case DatePlusUtils.NEXT_TYPE_YEAR:
                    calendar.add(Calendar.YEAR, nextStep);
                    break;
                case DatePlusUtils.NEXT_TYPE_MONTH:
                    calendar.add(Calendar.MONTH, nextStep);
                    break;
                case DatePlusUtils.NEXT_TYPE_DAY:
                    calendar.add(Calendar.DATE, nextStep);
                    break;
                case DatePlusUtils.NEXT_TYPE_HOUR:
                    calendar.add(Calendar.HOUR, nextStep);
                    break;
                case DatePlusUtils.NEXT_TYPE_MINUTE:
                    calendar.add(Calendar.MINUTE, nextStep);
                    break;
                case DatePlusUtils.NEXT_TYPE_SECOND:
                    calendar.add(Calendar.SECOND, nextStep);
                    break;
                default: break;
            }
            endDate = calendar.getTime();
        }
        return endDate;
    }

    /**
     * 字符串转换成日期 (注意: dateString 与 formatString 要匹配)<br>
     * @param dateString   需要转换的日期字符串
     * @param formatString 转换格式 yyyy-MM-dd HH:mm:ss 或 yyyy-MM-dd
     * @return java.util.Date
     */
    public static Date stringToDate(String dateString, String formatString) {
        Date returnValue = null;
        try {
            if (StringUtils.isNotBlank(dateString)) {
                SimpleDateFormat formatter = new SimpleDateFormat(formatString);
                // 设置时间分析为严格的
                formatter.setLenient(false);
                returnValue = formatter.parse(dateString);
            }
        } catch (Exception ex) {
            log.error("日期转换错误: " + dateString + " 指定格式 [" + formatString + "]，" + ex.getMessage(), ex);
            throw new BusinessException("日期转换错误: " + dateString + " 指定格式 [" + formatString + "]，" + ex.getMessage());
        }
        return returnValue;
    }

    /**
     * 字符串转换成日期 (注意: dateString 与 formatter 要匹配)<br>
     * @param dateString   需要转换的日期字符串
     * @param formatter 格式转换器
     * @return java.util.Date
     */
    public static Date stringToDate(String dateString, SimpleDateFormat formatter) {
        Date returnValue = null;
        try {
            if (StringUtils.isNotBlank(dateString)) {
                // 设置时间分析为严格的
                formatter.setLenient(false);
                returnValue = formatter.parse(dateString);
            }
        } catch (Exception ex) {
            log.error("日期转换错误: " + dateString + "，" + ex.getMessage(), ex);
            throw new BusinessException("日期转换错误: " + dateString + "，" + ex.getMessage());
        }
        return returnValue;
    }

    /**
     * 获取指定日期当周的第一天
     * @param date 指定日期
     * @return 指定日期当周的第一天
     */
    public static Date getWeekFirstDay(Date date){
        if(ObjectUtils.isEmpty(date)){
            date = new Date();
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.setFirstDayOfWeek(Calendar.MONDAY);
        cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /**
     * 获取指定日期当周的最后一天
     * @param date 指定日期
     * @return 指定日期当周的最后一天
     */
    public static Date getWeekLastDay(Date date){
        if(ObjectUtils.isEmpty(date)){
            date = new Date();
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.setFirstDayOfWeek(Calendar.MONDAY);
        cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /**
     * 获取指定日期当月的第一天
     * @param date 指定日期
     * @return 指定日期当月的第一天
     */
    public static Date getMonthFirstDay(Date date) {
        if(ObjectUtils.isEmpty(date)){
            date = new Date();
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /**
     * 获取指定日期当月的最后一天
     * @param date 指定日期
     * @return 指定日期当月的最后一天
     */
    public static Date getMonthLastDay(Date date) {
        if(ObjectUtils.isEmpty(date)){
            date = new Date();
        }
        // 获取下个月的第一天
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.DAY_OF_MONTH, +1);
        cal.roll(Calendar.DAY_OF_MONTH, -1);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /**
     * 获取指定月的最后一天
     * @param monthStr 月份字符串（yyyy-MM）
     * @return 指定月的最后一天
     */
    public static Date getMonthLastDay(String monthStr) {
        monthStr = monthStr + DatePlusUtils.MONTH_START_DATE;
        Date date = DatePlusUtils.stringToDate(monthStr, DatePlusUtils.FORMAT_DATE);
        // 获取下个月的第一天
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.DAY_OF_MONTH, +1);
        cal.roll(Calendar.DAY_OF_MONTH, -1);
        return cal.getTime();
    }

    /**
     * 计算两个日期之间相差的天数
     * @param startDate 较小的时间
     * @param endDate  较大的时间
     * @return 相差天数
     */
    public static int dateBetween(Date startDate, Date endDate) {
        try {
            startDate = DatePlusUtils.FORMATTER_DATE.parse(DatePlusUtils.FORMATTER_DATE.format(startDate));
            endDate = DatePlusUtils.FORMATTER_DATE.parse(DatePlusUtils.FORMATTER_DATE.format(endDate));
            Calendar cal = Calendar.getInstance();
            cal.setTime(startDate);
            long time1 = cal.getTimeInMillis();
            cal.setTime(endDate);
            long time2 = cal.getTimeInMillis();
            long between_days = (time2 - time1) / (DatePlusUtils.RADIX_MILLISECOND_IN_DAY);
            return Integer.parseInt(String.valueOf(between_days));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return 0;
    }

    /**
     * 计算两个日期之间相差的天数
     * @param startDate 较小的时间
     * @param endDate  较大的时间
     * @return 相差天数
     */
    public static Double dateBetween(Date startDate, Date endDate, String ksrqLx, String jsrqLx) {
        try {
            startDate = DatePlusUtils.FORMATTER_DATE.parse(DatePlusUtils.FORMATTER_DATE.format(startDate));
            endDate = DatePlusUtils.FORMATTER_DATE.parse(DatePlusUtils.FORMATTER_DATE.format(endDate));
            Calendar cal = Calendar.getInstance();
            cal.setTime(startDate);
            long time1 = cal.getTimeInMillis();
            cal.setTime(endDate);
            long time2 = cal.getTimeInMillis();
            long between_days = (time2 - time1) / (DatePlusUtils.RADIX_MILLISECOND_IN_DAY);
            Double sc = Double.valueOf(String.valueOf(between_days)) + 1;
            if("02".equals(ksrqLx)) {
                sc = sc - 0.5;
            }
            if("01".equals(jsrqLx)) {
                sc = sc - 0.5;
            }
            return sc;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return 0.0;
    }

    /**
     * 计算两个时间之间的差
     * @param date1 时间1
     * @param date2 时间2
     * @return 相差时间
     */
    public static String dateGap(String date1, String date2) {
        String zqsc = "";
        try {
            Date parse1 = DatePlusUtils.FORMATTER_DATE_TIME.parse(date1);
            Date parse2 = DatePlusUtils.FORMATTER_DATE_TIME.parse(date2);
            long time;
            if (parse1.before(parse2)) {
                time = parse2.getTime() - parse1.getTime();
            } else {
                time = parse1.getTime() - parse2.getTime();
            }
            long days = time / (DatePlusUtils.RADIX_MILLISECOND_IN_DAY);//天
            long hours = (time - days * (DatePlusUtils.RADIX_MILLISECOND_IN_DAY)) / (DatePlusUtils.RADIX_MILLISECOND_IN_HOUR);//小时
            long minutes = (time - days * (DatePlusUtils.RADIX_MILLISECOND_IN_DAY) - hours * (DatePlusUtils.RADIX_MILLISECOND_IN_HOUR)) / (DatePlusUtils.RADIX_MILLISECOND_IN_MINUTE);//分钟
            zqsc = days + "天" + hours + "小时" + minutes + "分钟";
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return zqsc;
    }

    /**
     * 两个年数据 相减
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 年份相减
     */
    public static Integer yearGap(Date startDate, Date endDate) {
        if(startDate == null || endDate == null){
            return null;
        }
        return endDate.getYear() - startDate.getYear();
    }

    /**
     * 比较2个日期间大小
     * date1在date2之前，返回true，date1在date2之后，返回false
     * @param date1 时间1字符串
     * @param date2 时间2字符串
     * @return date1是否在date2之前
     */
    public static boolean compareDateString(String date1, String date2) {
        try {
            Date dt1 = DatePlusUtils.FORMATTER_DATE_TIME.parse(date1);
            Date dt2 = DatePlusUtils.FORMATTER_DATE_TIME.parse(date2);
            return dt1.getTime() < dt2.getTime();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 比较2个日期间大小
     * date1在date2之前，返回true，date1在date2之后，返回false
     * @param date1 时间1
     * @param date2 时间2
     * @return boolean date1是否在date2之前
     */
    public static boolean compareDate(Date date1, Date date2) {
        try {
            return date1.getTime() < date2.getTime();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 计算日期是否在日期范围中
     * @param range1 日期范围开始时间
     * @param range2 日期范围结束时间
     * @param target 需要计算的日期
     * @return 是否在两个日期范围中，true表示在范围内，false表示在范围外
     */
    public static boolean betweenDateRange(Date range1, Date range2, Date target){
        if(range1 == null || range2 == null || target == null){
            return false;
        }
        return range1.getTime() <= target.getTime() && target.getTime() <= range2.getTime();
    }

    /**
     * 日期转星期
     * @param dateString 日期字符串
     * @return String
     */
    public static String dateToWeekReturnChinese(String dateString) {
        String[] weekDays = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
        // 获得一个日历
        Calendar cal = Calendar.getInstance();
        try {
            Date date = DatePlusUtils.FORMATTER_DATE.parse(dateString);
            cal.setTime(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        // 指示一个星期中的某天。
        int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (w < 0) {
            w = 0;
        }
        return weekDays[w];
    }

    /**
     * 日期转星期
     * @param date 日期
     * @return String
     */
    public static String dateToWeekReturnChinese(Date date) {
        String[] weekDays = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
        // 获得一个日历
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        // 指示一个星期中的某天。
        int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (w < 0) {
            w = 0;
        }
        return weekDays[w];
    }

    /**
     * 日期转星期
     * @param dateString 日期字符串
     * @return String
     */
    public static int dateToWeekReturnInt(String dateString) {
        // 获得一个日历
        Calendar cal = Calendar.getInstance();
        try {
            Date date = DatePlusUtils.FORMATTER_DATE.parse(dateString);
            cal.setTime(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        // 指示一个星期中的某天。
        int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (w < 0) {
            w = 0;
        }
        return w;
    }

    /**
     * 日期转星期
     * @param date 日期
     * @return int
     */
    public static int dateToWeekReturnInt(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (w < 0) w = 0;
        return w;
    }

    /**
     * 返回时间段里面的所有日期
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return List 日期字符串集合
     */
    public static List<String> getDays(String startDate, String endDate) {
        // 返回的日期集合
        List<String> days = new ArrayList<>();
        if(StringUtils.isBlank(startDate) || StringUtils.isBlank(endDate)) {
            return days;
        }
        try {
            Date start = DatePlusUtils.FORMATTER_DATE.parse(startDate);
            Date end = DatePlusUtils.FORMATTER_DATE.parse(endDate);

            Calendar tempStart = Calendar.getInstance();
            tempStart.setTime(start);

            Calendar tempEnd = Calendar.getInstance();
            tempEnd.setTime(end);
            tempEnd.add(Calendar.DATE, +1);// 日期加1(包含结束)
            while (tempStart.before(tempEnd)) {
                days.add(DatePlusUtils.FORMATTER_DATE.format(tempStart.getTime()));
                tempStart.add(Calendar.DAY_OF_YEAR, 1);
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return days;
    }

    /**
     * 返回时间段里面的所有日期
     * @param start 开始日期
     * @param end 结束日期
     * @return List 日期字符串集合
     */
    public static List<String> getDays(Date start, Date end) {
        // 返回的日期集合
        List<String> days = new ArrayList<>();
        if(ObjectUtils.isEmpty(start) || ObjectUtils.isEmpty(end)) {
            return days;
        }
        Calendar tempStart = Calendar.getInstance();
        tempStart.setTime(start);

        Calendar tempEnd = Calendar.getInstance();
        tempEnd.setTime(end);
        tempEnd.add(Calendar.DATE, +1);// 日期加1(包含结束)
        while (tempStart.before(tempEnd)) {
            days.add(DatePlusUtils.FORMATTER_DATE.format(tempStart.getTime()));
            tempStart.add(Calendar.DAY_OF_YEAR, 1);
        }
        return days;
    }

    /**
     * 将时间戳转为日期
     * @param stamp 时间戳
     * @return 日期
     */
    public static Date toTimeStamp(Long stamp){
        try{
            Calendar tempEnd = Calendar.getInstance();
            tempEnd.setTimeInMillis(stamp);
            return tempEnd.getTime();
        }catch (Exception e){
            return null;
        }
    }

    /**
     * 根据指定时间，获取指定的一周的指定星期
     * @param date 指定时间
     * @param weekDay 指定星期
     * @return 指定星期日期
     */
    public static Date getWeekDayDate(Date date, Integer weekDay) {
        int weekday = DatePlusUtils.dateToWeekReturnInt(date);
        if(weekday == weekDay){
            return date;
        }
        Date start = date;
        while(weekday != weekDay){
            start = DatePlusUtils.getNextDate(start, DatePlusUtils.NEXT_TYPE_DAY,1);
            weekday = DatePlusUtils.dateToWeekReturnInt(start);
        }
        return start;
    }

    /**
     * 获取今天日期
     * @return 今天
     */
    public static Date getToday(){
        return DatePlusUtils.stringToDate(DatePlusUtils.getSystemDateString(), DatePlusUtils.FORMAT_DATE);
    }

    /**
     * 获取今天结束时间
     * @return 今天结束时间
     */
    public static Date getTodayEnd(){
        return DatePlusUtils.stringToDate(DatePlusUtils.getSystemDateString() + DatePlusUtils.DAY_END_TIME, DatePlusUtils.FORMAT_DATE_TIME);
    }

    /**
     * 获取当前月份
     * @return 本月
     */
    public static Date getThisYearMonth(){
        return DatePlusUtils.stringToDate(DatePlusUtils.getSystemYearMonthString(), DatePlusUtils.FORMAT_YEAR_MONTH);
    }

    /**
     * 获取昨天日期开始，格式如: (2008-05-12)（不传日期则计算当前日期的前一天）
     * @param date 计算日期
     * @return 计算日期的前一天
     */
    public static Date getYesterdayBegin(Date date){
        return getOtherDateBegin(date, -1);
    }

    /**
     * 获取昨天日期，格式如: (2008-05-12 23:59:59)（不传日期则计算当前日期的前一天）
     * @param date 计算日期
     * @return 计算日期的前一天
     */
    public static Date getYesterdayEnd(Date date){
        return getOtherDateEnd(date, -1);
    }

    /**
     * 获取指定日期相差other天的日期，格式如: (2008-05-12)
     * @param date 指定日期
     * @param other 相差天数
     * @return Date 相差other天的日期，格式如: (2008-05-12)
     */
    public static Date getOtherDateBegin(Date date, int other){
        if(date == null){
            date = new Date();
        }
        return DatePlusUtils.stringToDate(
                DatePlusUtils.getDateString(DatePlusUtils.getNextDate(date, DatePlusUtils.NEXT_TYPE_DAY, other)),
                DatePlusUtils.FORMAT_DATE
        );
    }

    /**
     * 获取指定日期相差other天的日期，格式如: (2008-05-12 23:59:59)
     * @param date 指定日期
     * @param other 相差天数
     * @return Date 相差other天的日期，格式如: (2008-05-12 23:59:59)
     */
    public static Date getOtherDateEnd(Date date, int other){
        if(date == null){
            date = new Date();
        }
        return DatePlusUtils.stringToDate(
                DatePlusUtils.getDateString(DatePlusUtils.getNextDate(date, DatePlusUtils.NEXT_TYPE_DAY, other)) + DatePlusUtils.DAY_END_TIME,
                DatePlusUtils.FORMAT_DATE_TIME
        );
    }

    public static void main(String[] args) {
        try {
            System.out.println(DatePlusUtils.getDateTimeString(DatePlusUtils.getWeekFirstDay(DatePlusUtils.stringToDate("2024-03-15", DatePlusUtils.FORMAT_DATE))));
            System.out.println(DatePlusUtils.getDateTimeString(DatePlusUtils.getWeekLastDay(DatePlusUtils.stringToDate("2024-03-15", DatePlusUtils.FORMAT_DATE))));
            System.out.println(DatePlusUtils.getDateTimeString(DatePlusUtils.getMonthFirstDay(DatePlusUtils.stringToDate("2024-03-15", DatePlusUtils.FORMAT_DATE))));
            System.out.println(DatePlusUtils.getDateTimeString(DatePlusUtils.getMonthLastDay(DatePlusUtils.stringToDate("2024-03-15", DatePlusUtils.FORMAT_DATE))));
        } catch (Exception e){
            e.printStackTrace();
        }
    }

}
