package cn.kk.spring_simple_operation.utils;

import lombok.SneakyThrows;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;

import java.lang.management.ManagementFactory;
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.ChronoUnit;
import java.util.*;
import java.util.stream.Stream;


/**
 * @Author: sundl
 * @Date: 2021/08/18/10:42
 * @Description:时间工具类
 */

public class DateUtils {


	/**
	 * 当前时区偏移量 东八区
	 */
	private static final ZoneOffset SYSTEM_ZONE_OFFSET = OffsetDateTime.now().getOffset();
	/**
	 * 当前时区
	 */
	private static final ZoneId     SYSTEM_ZONE_ID     = ZoneId.systemDefault();

	public static final String YYYY = "yyyy";

	public static final String YYYY_MM = "yyyy-MM";

	public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";

	public static final String YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm";


	public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

	public static final String YYYY_MM_DD_T_HH_MM_SS_SSS_Z = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";


	public static final String YYYY_MM_DD = "yyyy-MM-dd";

	public static final String YYYYMMDD = "yyyyMMdd";

	public static final String YYYYMM = "yyyyMM";

	public static final String DOT_YYYY_MM_DD = "yyyy.MM.dd";


	private static final String[] parsePatterns = {
			"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
			"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
			"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM",
			"yyyyMMdd",

			// 匹配 【8/22/2022 1:00:53 上午 】这种格式
			"M/d/yyyy hh:mm:ss aa"
	};


	/**
	 * 将秒级时间戳格式化输出
	 * yyyy-MM-dd HH:mm:ss
	 *
	 * @param
	 */
	public static String format10timeStamp(Integer timeStamp) {
		long l = (long) timeStamp * 1000;
		//设置日期格式
		SimpleDateFormat sdf = new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS);
		return sdf.format(l);
	}

	/**
	 * 将秒级时间戳格式化输出
	 * yyyy-MM-dd HH:mm:ss
	 *
	 * @param
	 */
	public static String format10YMD(Integer timeStamp) {
		long l = (long) timeStamp * 1000;
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");//设置日期格式
		return sdf.format(l);
	}

	/**
	 * 将秒级时间戳格式化输出
	 * yyyy-MM-dd
	 *
	 * @param
	 */
	public static List<String> format10YMD(Integer backlogStartTimestamp, Integer backlogEndTimestamp) {
		// 将时间戳转换成Instant对象
		Instant startInstant = Instant.ofEpochSecond(backlogStartTimestamp);
		Instant endInstant = Instant.ofEpochSecond(backlogEndTimestamp);

		// 可选：转换时区（若不需要时区转换，可跳过此步骤）
		ZoneId zoneId = ZoneId.systemDefault(); // 或者使用ZoneId.of("时区代码")指定特定时区
		LocalDate startDate = startInstant.atZone(zoneId).toLocalDate();
		LocalDate endDate = endInstant.atZone(zoneId).toLocalDate();

		// 使用Stream生成日期范围并输出
		DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
		List<String> dateList = new ArrayList<>();
		Stream.iterate(startDate, date -> date.plusDays(1))
				.limit(endDate.toEpochDay() - startDate.toEpochDay() + 1)
				.forEach(date -> {
					String dateString = date.format(dateFormatter);
					dateList.add(dateString);
				});
		return dateList;
	}

	/**
	 * @param timeStr 待转化的Date字符串
	 * @description: utc时区 Date字符串转时间戳 秒级
	 * @return: java.util.Date
	 * @author: Devin
	 * @time: 2021/8/31
	 * @version: V1.0
	 */
	public static Integer utcToLocal(String timeStr) {
		//创建对应的pattern，注意T和Z两个字符使用单引号引起来，毫秒值使用大写S表示
		DateTimeFormatter pattern = DateTimeFormatter.ofPattern(YYYY_MM_DD_T_HH_MM_SS_SSS_Z);
		if (StringUtils.isEmpty(timeStr)) {
			timeStr = LocalDateTime.now().format(pattern);
		}
		//字符串时间转换成时间类型
		LocalDateTime localDateTime = LocalDateTime.parse(timeStr, pattern);
		//时间类型转时间戳类型 毫秒级转成秒级
		Long ts = (localDateTime.toInstant(ZoneOffset.UTC).toEpochMilli()) / 1000;

		return Integer.valueOf(ts.toString());
	}

	/**
	 * @description: 获取当前时间 秒级
	 * @return: java.lang.Integer
	 * @author: Devin
	 * @time: 2021/8/31
	 * @version: V1.0
	 */
	public static Integer getCurrentTimeSecond() {
		return (int) Instant.now().getEpochSecond();
	}


	/**
	 * 获取开始-结束时间内的一个随机时间
	 *
	 * @param startDay 开始时间
	 * @param endDay   结束时间
	 */
	public static int randomTime(String startDay, String endDay) {
		try {
			Date date1 = DateUtils.parseDate(startDay);
			Date date2 = DateUtils.parseDate(endDay);
			long second1 = date1.toInstant().getEpochSecond();
			long second2 = date2.toInstant().getEpochSecond();
			return (int) RandomUtils.nextLong(second1, second2);
		} catch (Exception e) {
			return 0;
		}
	}

	/**
	 * 秒级时间戳转为时间字符串,时间戳<=0时返回空字符串
	 *
	 * @param second
	 * @param format
	 * @return
	 */
	public static String formatTimeSecond(Integer second, String format) {
		Objects.requireNonNull(second);
		SimpleDateFormat formatter = null;
		try {
			formatter = new SimpleDateFormat(format);
		} catch (Exception e) {
			formatter = new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS);
		}
		return formatter.format(((long) second) * 1000);
	}

	public static String formatDate(Date date, String format) {
		if (date == null) return null;
		int second = (int) date.toInstant().getEpochSecond();
		return formatTimeSecond(second, format);
	}


	/**
	 * 重新格式化字符串
	 *
	 * @param dateStr
	 * @param formFormat
	 * @param toFormat
	 * @return
	 */
	public static String reFormatDate(String dateStr, String formFormat, String toFormat) {
		return DateUtils.formatDate(DateUtils.parseDate(dateStr, formFormat), toFormat);
	}


	/**
	 * 重新格式化日期 字符串解析 失败则返回null
	 *
	 * @param dateStr
	 * @param formFormat
	 * @param toFormat
	 * @return
	 */
	public static String reFormatLocalDate(String dateStr,
	                                       String formFormat,
	                                       String toFormat) {
		LocalDate localDate;
		try {
			localDate = DateUtils.parseLocalDate(dateStr, formFormat);
		} catch (Exception e) {
			return null;
		}
		try {
			return localDate.format(DateTimeFormatter.ofPattern(toFormat));
		} catch (Exception e) {
			return null;
		}

	}

	/**
	 * 重新格式化时间 字符串解析 失败则返回null
	 *
	 * @param dateStr
	 * @param formFormat
	 * @param toFormat
	 * @return
	 */
	public static String reFormatLocalDateTime(String dateStr,
	                                           String formFormat,
	                                           String toFormat) {
		LocalDateTime localDateTime;
		try {
			localDateTime = DateUtils.parseDateTime(dateStr, formFormat);
		} catch (Exception e) {
			return null;
		}

		try {
			return localDateTime.format(DateTimeFormatter.ofPattern(toFormat));
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * 解析时间字符为秒级时间戳
	 *
	 * @param dateStr
	 * @return
	 */
	public static Integer parseDateStr2TimeSecond(String dateStr) {
		if (StringUtils.isBlank(dateStr) || dateStr.startsWith("1970")) {
			return 0;
		}
		Date date = parseDate(dateStr);
		if (date == null) return 0;
		return (int) date.toInstant().getEpochSecond();
	}


	/**
	 * 日期转秒级时间戳
	 *
	 * @param date 如果是null 则为0
	 * @return
	 */
	public static Integer date2TimeSecond(Date date) {
		if (date != null) {
			int val = (int) date.toInstant().getEpochSecond();
			return val > 0 ? val : 0;
		} else {
			return 0;
		}
	}

	/**
	 * 日期转秒级时间戳
	 *
	 * @param date 如果是null 则为0
	 * @return
	 */
	public static Integer date2TimeSecondAfter2000(Date date) {
		if (date != null) {
			int val = (int) date.toInstant().getEpochSecond();
			return val > 943891200 ? val : 0;
		} else {
			return 0;
		}
	}


	public static Integer getEndOfDay(Date date, int dayOffset) {
		return getStartOfDay(date, dayOffset + 1) - 1;
	}

	/**
	 * 获取当天凌晨
	 */
	public static Integer getStartOfDay(Date date, int dayOffset) {
		if (date == null) return null;
		int offset = 24 * 3600 * dayOffset;
		LocalDate localDate = date.toInstant().atZone(SYSTEM_ZONE_ID).toLocalDate();
		return (int) localDate.atStartOfDay().toEpochSecond(SYSTEM_ZONE_OFFSET) + offset;
	}

	/**
	 * 传入的秒级别时间戳->秒级时间戳对应的当天00:00:00的时间戳->加上或减去日期偏移量
	 *
	 * @param timeSecond
	 * @param offsetDay
	 */
	public static Integer getStartOfDay(Integer timeSecond, int offsetDay) {
		Objects.requireNonNull(timeSecond);
		LocalDate localDate = Instant.ofEpochSecond(timeSecond).atZone(SYSTEM_ZONE_ID).toLocalDate();
		final int offset = offsetDay * 24 * 3600;
		return (int) (localDate.atStartOfDay().toEpochSecond(SYSTEM_ZONE_OFFSET) + offset);
	}


	/**
	 * @description: 获取过去 第 past 天的日期
	 * @return: java.lang.Integer
	 * @author: Devin
	 * @time: 2021/9/01
	 * @version: V1.0
	 */
	public static String getComingDate(int past, String formatStr) {
		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) + past);
		Date today = calendar.getTime();
		SimpleDateFormat format = new SimpleDateFormat(formatStr);
		String result = format.format(today);
		return result;
	}

	/**
	 * @description: 获取过去 第 past 天的日期
	 * @return: java.lang.Integer
	 * @author: Devin
	 * @time: 2021/9/01
	 * @version: V1.0
	 */
	public static String getFutureDate(int past, String formatStr) {
		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) - past);
		Date today = calendar.getTime();
		SimpleDateFormat format = new SimpleDateFormat(formatStr);
		String result = format.format(today);
		return result;
	}

	/**
	 * @param timestamp 时间戳
	 * @description: utc时区的时间戳转成秒的时间戳
	 * @return: java.lang.Integer
	 * @author: Devin
	 * @time: 2021/9/1
	 * @version: V1.0
	 */
	public static Integer millisecondToSecondTime(Long timestamp) {

		Calendar calendar = Calendar.getInstance();
		calendar.setTimeInMillis(timestamp);
		calendar.set(Calendar.HOUR, calendar.get(Calendar.HOUR) + 8);

		Long currentTimeSecond = calendar.getTimeInMillis() / 1000;
		return Integer.valueOf(String.valueOf(currentTimeSecond));
	}

	/**
	 * 时间转换指定小时
	 *
	 * @param timestamp 秒级时间戳
	 * @param type      0 -加 1-减
	 * @param hour      小时
	 * @return
	 */
	public static Integer timeConvertFixHour(Long timestamp, Integer type, Integer hour) {

		Calendar calendar = Calendar.getInstance();
		calendar.setTimeInMillis(timestamp);
		if (type == 1) {
			calendar.set(Calendar.HOUR, calendar.get(Calendar.HOUR) - hour);
		} else {
			calendar.set(Calendar.HOUR, calendar.get(Calendar.HOUR) + hour);
		}

		Long currentTimeSecond = calendar.getTimeInMillis() / 1000;
		return Integer.valueOf(String.valueOf(currentTimeSecond));
	}

	/**
	 * @param format
	 * @param date
	 * @return: java.lang.String
	 * @author: Devin
	 * @time: 2021/10/15
	 * @version: V1.0
	 * @description:
	 */
	public static final String parseDateToStr(final String format, final Date date) {

		if (StringUtils.isBlank(format) || date == null) {
			return null;
		}

		try {
			return new SimpleDateFormat(format).format(date);
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * 日期字符串 => 时间戳
	 */
	public static Integer parseDate(String str, String[] patterns) {
		if (StringUtils.isBlank(str)) return 0;
		try {
			Date date = org.apache.commons.lang3.time.DateUtils.parseDate(str.trim(), patterns);
			return (int) date.toInstant().getEpochSecond();
		} catch (ParseException e) {
			return null;
		}
	}


	@SneakyThrows
	public static Calendar parseDateV2(String str, String[] patterns) throws ParseException{
		if (StringUtils.isBlank(str)) return null;
		Date date = org.apache.commons.lang3.time.DateUtils.parseDate(str.trim(), patterns);
		Calendar calendar = getDefCalendar();
		calendar.setTime(date);
		return calendar;
	}


	public static Date fromUnixTime(final Integer unixTime) {
		if (unixTime == null) return null;
		return Date.from(Instant.ofEpochSecond(unixTime));

	}


	/**
	 *  漏洞：当传入字符是错误的时间字符，parseDate会根据解析规则得出错误的时间或null值，调用此方法前需确保字符的正确性
	 * 日期型字符串转化为日期 格式
	 * @author: Devin
	 */
	public static Date parseDate(Object str) {
		if (str == null) {
			return null;
		}
		try {
			return org.apache.commons.lang3.time.DateUtils.parseDate(str.toString(), parsePatterns);
		} catch (ParseException e) {
			return null;
		}
	}

	/**
	 * 解析日期字符串=>日期
	 *
	 * @param str    日期
	 * @param format 格式化
	 * @return 解析失败直接返回null
	 */
	public static Date parseDate(String str, String format) {
		if (StringUtils.isBlank(str)) {
			return null;
		}
		try {
			SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
			return simpleDateFormat.parse(str);
		} catch (ParseException e) {
			return null;
		}
	}


	/**
	 * 线程安全的format 时间格式化
	 */
	public static LocalDateTime parseDateTime(String str, String format) {
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
		return LocalDateTime.parse(str, formatter);
	}

	/**
	 * 日期格式化
	 */
	public static LocalDate parseLocalDate(String str, String format) {
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
		return LocalDate.parse(str, formatter);
	}


	/**
	 * @param millisecondTimestamp 毫秒级时间戳
	 * @return: java.lang.Integer
	 * @author: Devin
	 * @time: 2021/11/5
	 * @version: V1.0
	 * @description: 毫秒级时间戳转换成秒级时间戳
	 */
	public static Integer millisecondToSecondTimestamp(long millisecondTimestamp) {
		Long currentTimeSecond = millisecondTimestamp / 1000;
		return Integer.valueOf(String.valueOf(currentTimeSecond));
	}

	/**
	 * @param dateStr
	 * @return: java.lang.Integer
	 * @author: Devin
	 * @time: 2021/11/5
	 * @version: V1.0
	 * @description: 日期字符串转时间戳 秒级
	 */
	public static Integer dateStrToTimestamp(String dateStr, String timeFormat) {

		Date date = dateTime(timeFormat, dateStr);
		long longTime = date.getTime();
		return millisecondToSecondTimestamp(longTime);
	}

	/**
	 * @param format 时间格式
	 * @param ts     时间字符串
	 * @return: java.util.Date
	 * @author: Devin
	 * @time: 2021/11/5
	 * @version: V1.0
	 * @description: 把时间字符串按指定时间格式
	 */
	public static final Date dateTime(final String format, final String ts) {
		try {
			return new SimpleDateFormat(format).parse(ts);
		} catch (ParseException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 获取服务器启动时间
	 *
	 * @author: sundalin
	 */
	public static Date getServerStartDate() {
		long time = ManagementFactory.getRuntimeMXBean().getStartTime();
		return new Date(time);
	}

	/**
	 * 计算两个时间差
	 *
	 * @author: sundalin
	 */
	public static String getDatePoor(Date endDate, Date nowDate) {
		long nd = 1000 * 24 * 60 * 60;
		long nh = 1000 * 60 * 60;
		long nm = 1000 * 60;
		// long ns = 1000;
		// 获得两个时间的毫秒时间差异
		long diff = endDate.getTime() - nowDate.getTime();
		// 计算差多少天
		long day = diff / nd;
		// 计算差多少小时
		long hour = diff % nd / nh;
		// 计算差多少分钟
		long min = diff % nd % nh / nm;
		// 计算差多少秒//输出结果
		// long sec = diff % nd % nh % nm / ns;
		return day + "天" + hour + "小时" + min + "分钟";
	}

	/**
	 * 计算两个时间相差多少天
	 *
	 * @author: Devin
	 */
	public static Integer getDifferenceInDays(Integer endTime, Integer startTime) {
		long nd = 1000 * 24 * 60 * 60;

		long endDate = endTime * 1000;
		long startDate = startTime * 1000;
		int days = (int) ((endDate - startDate) / (nd));
		return days;
	}

	/**
	 * 获取当前日期, 默认格式为yyyy-MM-dd
	 *
	 * @return String
	 */
	public static String getDate() {
		return dateTimeNow(YYYY_MM_DD);
	}

	/**
	 * 获取当前时间。默认为格式 yyyy-MM-dd HH:mm:ss
	 * @return
	 */
	public static String getDateTime() {
		return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
	}

	public static final String dateTimeNow(final String format) {
		return parseDateToStr(format, new Date());
	}

	/**
	 * 获取当前Date型日期
	 *
	 * @return Date() 当前日期
	 */
	public static Date getNowDate() {
		return new Date();
	}


	private static Calendar getDefCalendar() {
		Calendar calendar = GregorianCalendar.getInstance(TimeZone.getDefault());
		calendar.set(Calendar.AM_PM, Calendar.PM);
		return calendar;
	}

	/**
	 * 传入时间戳获取季度中文名
	 */
	public static String getQuarterName(Integer unixTime) {
		if (unixTime == null) return null;
		Calendar calendar = DateUtils.getDefCalendar();
		calendar.setTime(Date.from(Instant.ofEpochSecond(unixTime)));
		int year = calendar.get(Calendar.YEAR);
		int month = calendar.get(Calendar.MONTH);
		int quarter = month / 3 + 1;
		return String.format("%s年第%s季度", year, quarter);
	}


	/**
	 * 获取季度开始时间戳
	 *
	 * @param year    年
	 * @param quarter 季度
	 */
	public static Integer getQuarterStart(int year, int quarter) {
		Assert.isTrue(quarter >= 1 && quarter <= 4, "季度必须在【1-4】之间");
		Calendar calendar = DateUtils.getDefCalendar();
		int startMonth = (quarter - 1) * 3 + 1;
		calendar.set(Calendar.YEAR, year);
		calendar.set(Calendar.MONTH, startMonth - 1);
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		calendar.set(Calendar.HOUR, -12);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		return DateUtils.date2TimeSecond(calendar.getTime());
	}

	/**
	 * 获取季度结束时间戳
	 *
	 * @param year    年
	 * @param quarter 季度
	 */
	public static Integer getQuarterEnd(int year, int quarter) {
		Assert.isTrue(quarter >= 1 && quarter <= 4, "季度必须在【1-4】之间");
		int endMonth = quarter * 3;
		Calendar calendar = DateUtils.getDefCalendar();
		// 设置年
		calendar.set(Calendar.YEAR, year);
		// 设置结束月的下一个月
		calendar.set(Calendar.MONTH, endMonth);
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		calendar.set(Calendar.HOUR, -12);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		// 注意减去一秒获取上个季度末
		return DateUtils.date2TimeSecond(calendar.getTime()) - 1;
	}


	/**
	 * 获取以当天为准的偏移天时间戳 的一天的开始
	 */
	public static Integer getStartOfDay(int dayOffset) {
		Date date = getDayFromNow(dayOffset);
		return DateUtils.date2TimeSecond(date);
	}


	/**
	 * 获取以当天为准的偏移天时间戳 的一天的结束
	 */
	public static Integer getEndOfDay(int dayOffset) {
		return getStartOfDay(dayOffset + 1) - 1;
	}

	/**
	 * 获取以当天为准的偏移天日期
	 */
	public static Date getDayFromNow(int datOffset) {
		Calendar calendar = DateUtils.getDefCalendar();
		// hour 严格 12小时制
		calendar.set(Calendar.HOUR, -12);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		calendar.add(Calendar.DATE, datOffset);

		return calendar.getTime();

	}


	/**
	 * 获取月份偏移量的第一天 0->当月月初  1下个月月初  -1上个月月初
	 */
	public static int getStartMonthOffset(Integer unixTime, int monthOffset) {
		Date from = Date.from(Instant.ofEpochSecond(unixTime));
		return DateUtils.date2TimeSecond(getStartMonthOffset(from, monthOffset));
	}

	public static Date getStartMonthOffset(Date date, int monthOffset) {
		Calendar calendar = DateUtils.getDefCalendar();
		calendar.setTime(date);
		calendar.add(Calendar.MONTH, monthOffset);
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		// hour 严格 12小时制
		//calendar.set(Calendar.HOUR, 0);
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		return calendar.getTime();
	}

	/**
	 * 给定时间戳,获取该时间的指定月份偏移量的月末
	 *
	 * @param unixTime
	 * @param monthOffset
	 * @return
	 */
	public static int getEndMonthOffset(Integer unixTime, int monthOffset) {
		Date date = DateUtils.getEndMonthOffset(DateUtils.fromUnixTime(unixTime), monthOffset);
		return DateUtils.date2TimeSecond(date);
	}


	public static Date getEndMonthOffset(Date date, int monthOffset) {
		Date nextMonthStart = DateUtils.getStartMonthOffset(date, monthOffset + 1);
		Integer unixTime = DateUtils.date2TimeSecond(nextMonthStart);
		return DateUtils.fromUnixTime(unixTime - 1);
	}

	/**
	 * 获取月初日期
	 *
	 * @param year
	 * @param month
	 * @return
	 */
	public static Date getStartOfMonth(int year, int month) {
		Assert.isTrue(month <= 12 && month >= 0, "月份不合法!");
		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.YEAR, year);
		calendar.set(Calendar.MONTH, (month - 1));
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		return calendar.getTime();
	}

	/**
	 * 获取月末日期
	 *
	 * @param year
	 * @param month
	 * @return
	 */
	public static Date geEndOfMonth(int year, int month) {
		Assert.isTrue(month <= 12 && month >= 0, "月份不合法!");
		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.YEAR, year);
		calendar.set(Calendar.MONTH, month);
		calendar.set(Calendar.DAY_OF_MONTH, 0);
		return calendar.getTime();
	}


	/**
	 * 获取当前月份偏移量的第一天 0->当月月初  1下个月月初  -1上个月月初
	 */
	public static int getStartOfMonth(int monthOffset) {
		return DateUtils.getStartMonthOffset(DateUtils.getCurrentTimeSecond(), monthOffset);
	}


	/**
	 * 获取月份偏移量的最后一天 0->当月月末  1下个月月末  -1上个月月末
	 */
	public static int getEndOfMonth(int monthOffset) {
		return DateUtils.getEndMonthOffset(DateUtils.getCurrentTimeSecond(), monthOffset);
	}


	/**
	 * 获取两天之间的日期间隔
	 */
	public static int rangeDay(Integer dayOne, Integer dayTwo, RoundingMode mode) {
		BigDecimal one = BigDecimal.valueOf(Optional.ofNullable(dayOne).orElse(0));
		BigDecimal two = BigDecimal.valueOf(Optional.ofNullable(dayTwo).orElse(0));
		BigDecimal oneDay = new BigDecimal(3600 * 24);
		BigDecimal result = two.subtract(one).divide(oneDay, mode);
		return Math.abs(result.intValue());
	}


	public static Double rangeDay(Integer dayOne, Integer dayTwo) {
		BigDecimal one = BigDecimal.valueOf(Optional.ofNullable(dayOne).orElse(0));
		BigDecimal two = BigDecimal.valueOf(Optional.ofNullable(dayTwo).orElse(0));
		BigDecimal oneDay = new BigDecimal(3600 * 24);
		BigDecimal result = two.subtract(one).divide(oneDay, 1, BigDecimal.ROUND_HALF_UP);
		return Math.abs(result.doubleValue());
	}


	/**
	 * 获取两天之间的工作日的时间间隔【去掉星期六和星期天】
	 *
	 * @param dayOne
	 * @param dayTwo
	 */
	public static int rangeWorkDay(Integer dayOne, Integer dayTwo) {
		Date start = Date.from(Instant.ofEpochSecond(Math.min(dayOne, dayTwo)));
		Date end = Date.from(Instant.ofEpochSecond(Math.max(dayOne, dayTwo)));
		Calendar startCal = Calendar.getInstance();
		Calendar endCal = Calendar.getInstance();
		startCal.setTime(start);
		endCal.setTime(end);

		// 获取距离下个星期天的天数
		int a = 0;
		while (startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY) {
			startCal.add(Calendar.DAY_OF_MONTH, 1);
			if (startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY && startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY) {
				a++;
			}
		}

		// 获取距离下个星期天的天数
		int b = 0;
		while (endCal.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY) {
			endCal.add(Calendar.DAY_OF_MONTH, 1);
			if (endCal.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY && endCal.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY) {
				b++;
			}
		}

		return ((endCal.get(Calendar.DAY_OF_YEAR) - startCal.get(Calendar.DAY_OF_YEAR)) * 5 / 7) + a - b;
	}

	/**
	 * 获取日期是星期几
	 * <p>
	 * * @see #SUNDAY
	 * * @see #MONDAY
	 * * @see #TUESDAY
	 * * @see #WEDNESDAY
	 * * @see #THURSDAY
	 * * @see #FRIDAY
	 * * @see #SATURDAY
	 *
	 * @param date 日期
	 */
	public static int getWeekDay(Date date) {
		Calendar instance = Calendar.getInstance();
		instance.setTime(date);
		return instance.get(Calendar.DAY_OF_WEEK);
	}


	/**
	 * 根据指定月份 获取月份偏移量
	 *
	 * @param year   年份
	 * @param month  月份
	 * @param offset 偏移量
	 * @return
	 */
	public static String getMonthOffset(int year, int month, int offset) {
		TimeZone timeZone = TimeZone.getDefault();
		Calendar calendar = Calendar.getInstance(timeZone);

		calendar.set(Calendar.YEAR, year);
		calendar.set(Calendar.MONTH, (month - 1) + offset);
		calendar.set(Calendar.DAY_OF_MONTH, 1);

		Date time = calendar.getTime();

		return DateUtils.formatDate(time, DateUtils.YYYY_MM);
	}


	public static LocalDate date2LocalDate(Date date) {
		if (date != null) {
			Instant instant = date.toInstant();
			return instant.atZone(ZoneId.systemDefault()).toLocalDate();
		}
		return null;
	}


	public static Calendar date2Calendar(Date date) {
		Calendar calendar = getDefCalendar();
		calendar.setTime(date);
		return calendar;
	}

	public static Long calculateTimeDifference(String startTime ,String endTime,String formatterStr) {
		// 定义日期时间格式
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatterStr);

		// 解析日期时间字符串为 LocalDateTime 对象
		LocalDateTime arrivalTime = LocalDateTime.parse(startTime, formatter);
		LocalDateTime createdTime = LocalDateTime.parse(endTime, formatter);

		// 计算时间差
		Long timeDiff = ChronoUnit.SECONDS.between(createdTime, arrivalTime);

		return timeDiff;
	}
}
