package com.ff.base.utils;

import org.apache.commons.lang3.time.DateFormatUtils;

import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;


/**
 * 时间工具类
 *
 * @author ff
 */
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
    public static String YYYY = "yyyy";

    public static String YYYY_MM = "yyyy-MM";

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

    public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";

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

    public static 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"};

    public static String HHMMSS = "HH:mm:ss";

    public static String DAY_START_TIME = "00:00:00";

    public static String DAY_END_TIME = "23:59:59";

    /**
     * 获取当前Date型日期
     *
     * @return Date() 当前日期
     */
    public static Long getNowDate() {
        return Instant.now().toEpochMilli();
    }


    /**
     * 获取当前日期
     *
     * @return {@link Long }
     */
    public static Date getCurrentDate() {
        return new Date();
    }

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

    public static final String getTime() {
        return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
    }

    public static final String dateTimeNow() {
        return dateTimeNow(YYYYMMDDHHMMSS);
    }

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

    public static final String dateTime(final Date date) {
        return parseDateToStr(YYYY_MM_DD, date);
    }

    public static final String parseDateToStr(final String format, final Date date) {
        return new SimpleDateFormat(format).format(date);
    }

    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);
        }
    }

    /**
     * 日期路径 即年/月/日 如2018/08/08
     */
    public static final String datePath() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyy/MM/dd");
    }

    /**
     * 日期路径 即年/月/日 如20180808
     */
    public static final String dateTime() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyyMMdd");
    }

    /**
     * 日期型字符串转化为日期 格式
     */
    public static Date parseDate(Object str) {
        if (str == null) {
            return null;
        }
        try {
            return parseDate(str.toString(), parsePatterns);
        } catch (ParseException e) {
            return null;
        }
    }

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

    /**
     * 计算相差天数
     */
    public static int differentDaysByMillisecond(Date date1, Date date2) {
        return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
    }

    /**
     * 计算时间差
     *
     * @param endDate   最后时间
     * @param startTime 开始时间
     * @return 时间差（天/小时/分钟）
     */
    public static String timeDistance(Date endDate, Date startTime) {
        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        // long ns = 1000;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - startTime.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 + "分钟";
    }

    /**
     * 增加 LocalDateTime ==> Date
     */
    public static Date toDate(LocalDateTime temporalAccessor) {
        ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
        return Date.from(zdt.toInstant());
    }

    /**
     * 获取格式化日期yymmd
     *
     * @return {@link String }
     */
    public static String getFormattedDate() {
        ZonedDateTime nowUtcMinus4 = ZonedDateTime.now(ZoneId.of("UTC-4"));

        String year = String.format("%02d", nowUtcMinus4.getYear() % 100);
        String month = String.format("%02d", nowUtcMinus4.getMonthValue());
        String day = String.valueOf(nowUtcMinus4.getDayOfMonth());

        return year + month + day;
    }

    /**
     * 将日期格式化为gmt4
     *
     * @param date 日期
     * @return {@link String }
     */
    public static String formatDateToGMT4(Date date) {
        // 将 Date 转换为 ZonedDateTime
        ZonedDateTime zdt = ZonedDateTime.ofInstant(date.toInstant(), ZoneId.of("GMT-4"));
        // 定义日期时间格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
        // 格式化并返回字符串
        return zdt.format(formatter);
    }

    /**
     * 增加 LocalDate ==> Date
     */
    public static Date toDate(LocalDate temporalAccessor) {
        LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
        ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
        return Date.from(zdt.toInstant());
    }


    /**
     * 给定毫秒级时间戳，增加或扣除指定分钟
     *
     * @param timestampMillis 初始时间戳（毫秒级）
     * @param minutes         要增加或扣除的分钟数（正值为增加，负值为扣除）
     * @return long 结果时间戳（毫秒级）
     */
    public static long addOrSubtractMinutes(long timestampMillis, int minutes) {
        // 将分钟转换为毫秒，并加到时间戳上
        return timestampMillis + minutes * 60 * 1000L;
    }

    /**
     * 加或减一天
     *
     * @param timestampDay 时间戳日期
     * @param day          白天
     * @return long
     */
    public static long addOrSubtractDay(long timestampDay, int day) {
        // 将分钟转换为毫秒，并加到时间戳上
        return timestampDay + day * 60 * 1000L * 60 * 24;
    }


    /**
     * 获取给定日期
     *
     * @return 不带时区的给定日期的起始时间戳（毫秒）
     */
    public static Long getDayStart(Calendar calendar) {
        // 设置时间为当天的 00:00:00
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取指定时间戳指定时区的一天的开始时间
     *
     * @param timestamp  时间戳
     * @param timeZoneId 时区
     * @return 时间戳
     */
    public static Long getDayStart(long timestamp, String timeZoneId) {
        ZoneId zoneId = ZoneId.of(timeZoneId);
        ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(java.time.Instant.ofEpochMilli(timestamp), zoneId);
        LocalDate localDate = zonedDateTime.toLocalDate();
        LocalDateTime startOfDay = localDate.atStartOfDay();
        ZonedDateTime startOfDayZoned = startOfDay.atZone(zoneId);
        return startOfDayZoned.toInstant().toEpochMilli();
    }

    /**
     * 获取给定日期
     *
     * @return 不带时区的给定日期的结束时间戳（毫秒）
     */
    public static Long getDayEnd(Calendar calendar) {
        // 设置时间为当天的 23:59:59
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取指定时间戳指定时区的一天的结束时间
     *
     * @param timestamp  时间戳
     * @param timeZoneId 时区
     * @return 时间戳
     */
    public static Long getDayEnd(long timestamp, String timeZoneId) {
        ZoneId zoneId = ZoneId.of(timeZoneId);
        ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(java.time.Instant.ofEpochMilli(timestamp), zoneId);
        LocalDate localDate = zonedDateTime.toLocalDate();
        LocalDateTime endOfDay = localDate.atTime(23, 59, 59, 999999999);
        ZonedDateTime endOfDayZoned = endOfDay.atZone(zoneId);
        return endOfDayZoned.toInstant().toEpochMilli();
    }

    /**
     * 获取昨天的开始时间（不带时区）
     *
     * @return 时间戳
     */
    public static Long getYesterdayStart() {
        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
        // 回溯一天
        calendar.add(Calendar.DAY_OF_MONTH, -1);
        // 设置时间为当天的 00:00:00
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取昨天的结束时间（不带时区）
     *
     * @return 时间戳
     */
    public static Long getYesterdayEnd() {
        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
        // 回溯一天
        calendar.add(Calendar.DAY_OF_MONTH, -1);
        // 设置时间为当天的 23:59:59
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取上周的开始时间（不带时区）
     *
     * @return 时间戳
     */
    public static Long getLastWeekBegin() {
        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
        // 计算上周的起始日期（周一）
        calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        calendar.add(Calendar.WEEK_OF_YEAR, -1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTimeInMillis();
    }


    /**
     * 获取上周的结束时间（不带时区）
     *
     * @return 时间戳
     */
    public static Long getLastWeekEnd() {
        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
        // 计算上周的结束日期（周日）
        calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取一周的开始时间
     *
     * @return 时间戳
     */
    public static Long getWeekBegin(Calendar calendar) {
        // 设置一周的第一天为星期一
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        // 获取当前日期在本周的位置
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
        // 计算需要回溯的天数
        int daysToSubtract = (dayOfWeek == Calendar.SUNDAY ? 6 : dayOfWeek - 2);
        calendar.add(Calendar.DAY_OF_MONTH, -daysToSubtract);
        // 设置时间为当天的 00:00:00
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取一周的结束时间
     *
     * @return 时间戳
     */
    public static Long getWeekEnd(Calendar calendar) {
        // 设置一周的第一天为星期一
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        // 获取当前日期在本周的位置
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
        // 计算需要前进的天数
        int daysToAdd = (dayOfWeek == Calendar.SUNDAY ? 0 : 7 - (dayOfWeek - 1));
        calendar.add(Calendar.DAY_OF_MONTH, daysToAdd);
        // 设置时间为当天的 23:59:59
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取当前月份的开始时间
     *
     * @return 时间戳
     */
    public static Long getMonthStart(Calendar calendar) {
        // 设置时间为当月的第一天
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        // 设置时间为当天的 00:00:00
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取当前月份的结束时间（不带时区）
     *
     * @return 时间戳
     */
    public static Long getMonthEnd(Calendar calendar) {
        // 设置时间为当月的最后一天
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        // 设置时间为当天的 23:59:59
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取上个月的开始时间（不带时区）
     *
     * @return 时间戳
     */
    public static Long getLastMonthStart() {
        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
        // 计算上个月的起始日期（1号）
        calendar.add(Calendar.MONTH, -1);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取上个月的结束时间（不带时区）
     *
     * @return 时间戳
     */
    public static Long getLastMonthEnd() {
        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
        calendar.add(Calendar.MONTH, -1); // 回退一个月

        // 计算上个月的结束日期（最后一天）
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH)); // 设置日期为当月最后一天
        calendar.set(Calendar.HOUR_OF_DAY, 23); // 设置小时为23
        calendar.set(Calendar.MINUTE, 59); // 设置分钟为59
        calendar.set(Calendar.SECOND, 59); // 设置秒为59
        calendar.set(Calendar.MILLISECOND, 999); // 设置毫秒为999
        return calendar.getTimeInMillis();
    }


    /**
     * 判断时间戳 A 距离时间戳 B 近还是距离时间戳 C 近
     *
     * @param timestampA 时间戳 A
     * @param timestampB 时间戳 B
     * @param timestampC 时间戳 C
     * @return 返回 true 表示时间戳 A 更接近时间戳 B，返回 false 表示时间戳 A 更接近时间戳 C
     */
    public static boolean isCloserToB(long timestampA, long timestampB, long timestampC) {
        long diffAB = Math.abs(timestampA - timestampB);
        long diffAC = Math.abs(timestampA - timestampC);
        return diffAB < diffAC;
    }


    /**
     * 获取指定时间戳次日指定时区指定时间的时间戳
     *
     * @param utcTimestamp utc时间戳
     * @param date         具体时间
     * @param timeZonId    指定时区
     * @return 只改变时区 不改变具体日期的时间戳
     */
    public static long getTomorrowTimeByZonId(long utcTimestamp, Date date, String timeZonId) {
        SimpleDateFormat sdf = new SimpleDateFormat(HHMMSS);
        String format = sdf.format(date);
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern(HHMMSS);
        LocalTime localTime = LocalTime.parse(format, timeFormatter);
        // 将时间戳转换为 Instant
        Instant instant = Instant.ofEpochMilli(addOrSubtractDay(utcTimestamp, 1));
        ZoneId zoneId = ZoneId.of(timeZonId);
        LocalDate localDate = instant.atZone(zoneId).toLocalDate();
        LocalDateTime tomorrowDrawStartTime = localDate.atTime(localTime);
        return tomorrowDrawStartTime.atZone(zoneId).toInstant().toEpochMilli();
    }


    /**
     * 指定时区并具体时间的的实时时间戳
     *
     * @param date      具体时间
     * @param timeZonId 时区
     * @return 只改变时区 不改变具体日期的时间戳
     */
    public static long getTodayTimeByZonId(Date date, String timeZonId) {
        // 获取今日指定时间后的时间戳
        SimpleDateFormat sdf = new SimpleDateFormat(HHMMSS);
        String format = sdf.format(date);
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern(HHMMSS);
        LocalTime localTime = LocalTime.parse(format, timeFormatter);
        LocalDate currentDate = LocalDate.now();
        LocalDateTime todayDrawStartTime = currentDate.atTime(localTime);
        ZoneId zoneId = ZoneId.of(timeZonId);
        return todayDrawStartTime.atZone(zoneId).toInstant().toEpochMilli();
    }

    /**
     * 获取下周指定周几的几点的指定时区时间戳
     *
     * @param dayOfWeek 周几，1-7表示周一到周日
     * @param date      具体时间，Date对象
     * @return UTC时间戳（毫秒）
     */
    public static long getNextWeekTimestamp(int dayOfWeek, Date date, ZoneId zoneId) {
        // 将Date对象转换为LocalDateTime对象
        SimpleDateFormat sdf = new SimpleDateFormat(HHMMSS);
        String format = sdf.format(date);
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern(HHMMSS);
        LocalTime localTime = LocalTime.parse(format, timeFormatter);
        // 获取当前日期时间
        ZonedDateTime now = ZonedDateTime.now(zoneId);
        // 找到本周的周几
        ZonedDateTime startOfWeek = now.with(dayOfWeek < now.getDayOfWeek().getValue() ? TemporalAdjusters.previousOrSame(DayOfWeek.of(dayOfWeek)) : TemporalAdjusters.nextOrSame(DayOfWeek.of(dayOfWeek)));

        // 加上一个完整的星期，得到下周的周几
        ZonedDateTime nextWeekStart = startOfWeek.plusWeeks(1);

        // 设置指定的时间
        ZonedDateTime targetDateTime = nextWeekStart.withHour(localTime.getHour()).withMinute(localTime.getMinute()).withSecond(localTime.getSecond()).withNano(0);

        // 转换为时间戳（毫秒）
        return targetDateTime.toInstant().toEpochMilli();
    }

    /**
     * 获取指定时区当前周指定周几的几点的时间戳
     *
     * @param dayOfWeek 周几，1-7表示周一到周日
     * @param date      具体时间，Date对象
     * @return 时间戳（毫秒）
     */
    public static long getCurrentWeekTimestamp(int dayOfWeek, Date date, ZoneId zoneId) {
        // 将Date对象转换为LocalDateTime对象
        SimpleDateFormat sdf = new SimpleDateFormat(HHMMSS);
        String format = sdf.format(date);
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern(HHMMSS);
        LocalTime localTime = LocalTime.parse(format, timeFormatter);

        // 获取当前日期时间
        LocalDateTime now = LocalDateTime.now();

        // 获取当前周的指定周几的日期时间
        LocalDateTime currentWeekDateTime = now.with(dayOfWeek < now.getDayOfWeek().getValue() ? TemporalAdjusters.previousOrSame(DayOfWeek.of(dayOfWeek)) : TemporalAdjusters.nextOrSame(DayOfWeek.of(dayOfWeek)))
                .withHour(localTime.getHour())
                .withMinute(localTime.getMinute())
                .withSecond(localTime.getSecond())
                .withNano(0);

        // 将LocalDateTime转换为ZonedDateTime，使用UTC时区
        ZonedDateTime zonedDateTime = currentWeekDateTime.atZone(zoneId);

        // 将ZonedDateTime转换为时间戳（毫秒）
        return zonedDateTime.toInstant().toEpochMilli();
    }

    /**
     * 获取下月指定日的几点的时间戳
     *
     * @param dayOfMonth 指定日，1-31表示
     * @param date       具体时间，Date对象
     * @param month      下几月
     * @return 时间戳（毫秒）
     */
    public static long getNextMonthTimestamp(int dayOfMonth, Date date, ZoneId zoneId, int month) {
        // 将Date对象转换为LocalDateTime对象
        SimpleDateFormat sdf = new SimpleDateFormat(HHMMSS);
        String format = sdf.format(date);
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern(HHMMSS);
        LocalTime localTime = LocalTime.parse(format, timeFormatter);

        // 获取当前日期时间
        LocalDateTime now = LocalDateTime.now();

        // 获取下个月的年份和月份
        YearMonth nextMonth = YearMonth.from(now).plusMonths(month);
        int maxDayNum = nextMonth.lengthOfMonth();
        if (dayOfMonth > maxDayNum) {
            dayOfMonth = maxDayNum;
        }

        // 创建下个月指定日的LocalDateTime对象
        LocalDateTime nextMonthDateTime = LocalDateTime.of(nextMonth.getYear(), nextMonth.getMonth(), dayOfMonth,
                localTime.getHour(), localTime.getMinute(), localTime.getSecond(), 0);

        // 将LocalDateTime转换为ZonedDateTime，使用UTC时区
        ZonedDateTime zonedDateTime = nextMonthDateTime.atZone(zoneId);

        // 将ZonedDateTime转换为时间戳（毫秒）
        return zonedDateTime.toInstant().toEpochMilli();
    }

    /**
     * 获取本月指定日的几点的时间戳
     *
     * @param dayOfMonth 指定日，1-31表示
     * @param date       具体时间，Date对象
     * @return 时间戳（毫秒）
     */
    public static long getCurrentMonthTimestamp(int dayOfMonth, Date date, ZoneId zoneId) {
        // 将Date对象转换为LocalDateTime对象
        SimpleDateFormat sdf = new SimpleDateFormat(HHMMSS);
        String format = sdf.format(date);
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern(HHMMSS);
        LocalTime localTime = LocalTime.parse(format, timeFormatter);

        // 获取当前日期时间
        LocalDateTime now = LocalDateTime.now();
        // 获取本月的年份和月份
        YearMonth currentMonth = YearMonth.from(now);
        int maxDayNum = currentMonth.lengthOfMonth();
        if (dayOfMonth > maxDayNum) {
            dayOfMonth = maxDayNum;
        }

        // 创建本月指定日的LocalDateTime对象
        LocalDateTime currentMonthDateTime = LocalDateTime.of(currentMonth.getYear(), currentMonth.getMonth(), dayOfMonth,
                localTime.getHour(), localTime.getMinute(), localTime.getSecond(), 0);

        // 将LocalDateTime转换为ZonedDateTime，使用UTC时区
        ZonedDateTime zonedDateTime = currentMonthDateTime.atZone(zoneId);

        // 将ZonedDateTime转换为时间戳（毫秒）
        return zonedDateTime.toInstant().toEpochMilli();
    }


    /**
     * 将时间戳转换为UTC0时区的时间戳
     *
     * @param timeZoneId 时区id
     * @param timestamp  时间戳
     * @return UTC0时区的时间戳
     */
    public static long covertToUTCtimestamp(String timeZoneId, long timestamp) {
        // 将时间戳转换为 Instant 对象
        Instant instant = Instant.ofEpochMilli(timestamp);

        // 使用指定的时区将 Instant 对象转换为 ZonedDateTime 对象
        ZonedDateTime zonedDateTime = instant.atZone(ZoneId.of(timeZoneId));
        ZonedDateTime zonedDateTime1 = zonedDateTime.withZoneSameLocal(ZoneOffset.UTC);
        // 将 ZonedDateTime 对象转换为 UTC0 时区的 Instant 对象

        // 获取 UTC0 时区的时间戳（以毫秒为单位）
        return zonedDateTime1.toInstant().toEpochMilli();
    }

    /**
     * 将UTC时间戳转换为指定时区的时间戳
     *
     * @param timeZoneId 时区id
     * @param timestamp  时间戳
     * @return 指定时区的时间戳
     */
    public static long covertUTCTotimeZonetimestamp(String timeZoneId, long timestamp) {
        // 将时间戳转换为 Instant 对象
        Instant instant = Instant.ofEpochMilli(timestamp);

        // 使用指定的时区将 Instant 对象转换为 ZonedDateTime 对象
        ZonedDateTime zonedDateTime = instant.atZone(ZoneOffset.UTC);
        ZonedDateTime zonedDateTime1 = zonedDateTime.withZoneSameLocal(ZoneId.of(timeZoneId));
        // 获取 指定 时区的时间戳（以毫秒为单位）
        return zonedDateTime1.toInstant().toEpochMilli();
    }

    /**
     * 判断是否是指定时区的当天的0点
     *
     * @param timestamp
     * @param timeZone
     * @return
     */
    public static boolean isMidnight(long timestamp, TimeZone timeZone) {
        Calendar calendar = Calendar.getInstance(timeZone);
        calendar.setTimeInMillis(timestamp);

        return calendar.get(Calendar.HOUR_OF_DAY) == 0 &&
                calendar.get(Calendar.MINUTE) == 0 &&
                calendar.get(Calendar.SECOND) == 0 &&
                calendar.get(Calendar.MILLISECOND) == 0;
    }

    /**
     * 判断是否是指定时区的周一的0点
     *
     * @param timestamp 时间戳
     * @param timeZone  指定时区
     * @return 是否是周一的0点
     */
    public static boolean isMondayMidnight(long timestamp, TimeZone timeZone) {
        Calendar calendar = Calendar.getInstance(timeZone);
        calendar.setTimeInMillis(timestamp);

        return isMidnight(timestamp, timeZone) && calendar.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY;
    }

    /**
     * 将 ISO 8601 格式的时间字符串转换为毫秒时间戳
     *
     * @param isoDate ISO 8601 格式的时间字符串，例如 "2025-05-10T08:23:34Z"
     * @return 从 Unix epoch 开始的毫秒时间戳
     */
    public static long convertToMilliseconds(String isoDate) {
        Instant instant = Instant.parse(isoDate);
        return instant.toEpochMilli();
    }


    /**
     * 将 ZoneId 转换为 TimeZone
     *
     * @param zoneId 要转换的 ZoneId
     * @return 对应的 TimeZone
     */
    public static TimeZone zoneIdToTimeZone(ZoneId zoneId) {
        return TimeZone.getTimeZone(zoneId.getId());
    }

    /**
     * 获取指定星期几的开始和结束UTC时间戳
     *
     * @param dayOfWeek 星期几，1-7，1表示星期一，7表示星期日
     * @return 包含开始和结束UTC时间戳的数组，第一个元素是开始时间戳，第二个元素是结束时间戳
     */
    public static Map<String, Object> getStartAndEndUTCTimestampOfDayOfWeek(int dayOfWeek) {
        if (dayOfWeek < 1 || dayOfWeek > 7) {
            throw new IllegalArgumentException("dayOfWeek must be between 1 and 7");
        }

        // 获取当前日期
        LocalDate today = LocalDate.now(ZoneOffset.UTC);
        // 计算本周的开始日期（星期一）
        LocalDate monday = today.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        // 计算指定星期几的日期
        LocalDate targetDay = monday.plusDays(dayOfWeek - 1);

        // 计算指定星期几的开始时间（00:00:00 UTC）
        ZonedDateTime startOfDay = targetDay.atStartOfDay(ZoneOffset.UTC);
        // 计算指定星期几的结束时间（23:59:59 UTC）
        ZonedDateTime endOfDay = targetDay.atTime(LocalTime.MAX).atZone(ZoneOffset.UTC);

        // 获取开始和结束时间戳
        long startTimestamp = startOfDay.toInstant().toEpochMilli();
        long endTimestamp = endOfDay.toInstant().toEpochMilli();

        Map<String, Object> map = new HashMap<>();
        map.put("beginTime", startTimestamp);
        map.put("endTime", endTimestamp);
        return map;
    }

    /**
     * 获取本月指定月几号的开始和结束UTC时间戳
     *
     * @param dayOfMonth 本月几号，1-31
     * @return 包含开始和结束UTC时间戳的Map，键分别为"beginTime"和"endTime"
     */
    public static Map<String, Object> getStartAndEndUTCTimestampOfDayOfMonth(int dayOfMonth) {
        // 获取当前日期
        LocalDate today = LocalDate.now(ZoneOffset.UTC);
        // 获取本月的年份和月份
        YearMonth currentMonth = YearMonth.from(today);
        int maxDayNum = currentMonth.lengthOfMonth();
        if (dayOfMonth > maxDayNum) {
            dayOfMonth = maxDayNum;
        }
        // 获取当前年份和月份
        int year = today.getYear();
        int month = today.getMonthValue();

        // 构建指定月几号的日期
        LocalDate targetDay;
        try {
            targetDay = LocalDate.of(year, month, dayOfMonth);
        } catch (DateTimeException e) {
            throw new IllegalArgumentException("Invalid dayOfMonth for the current month", e);
        }

        // 计算指定月几号的开始时间（00:00:00 UTC）
        ZonedDateTime startOfDay = targetDay.atStartOfDay(ZoneOffset.UTC);
        // 计算指定月几号的结束时间（23:59:59 UTC）
        ZonedDateTime endOfDay = targetDay.atTime(LocalTime.MAX).atZone(ZoneOffset.UTC);

        // 获取开始和结束时间戳
        long startTimestamp = startOfDay.toInstant().toEpochMilli();
        long endTimestamp = endOfDay.toInstant().toEpochMilli();

        Map<String, Object> map = new HashMap<>();
        map.put("beginTime", startTimestamp);
        map.put("endTime", endTimestamp);
        return map;
    }

    /**
     * 判断两个毫秒级时间戳是否为同一天
     *
     * @param timestamp1 第一个时间戳
     * @param timestamp2 第二个时间戳
     * @return 如果两个时间戳属于同一天，返回true；否则返回false
     */
    public static boolean isSameDay(long timestamp1, long timestamp2) {
        // 将时间戳转换为 LocalDate
        LocalDate date1 = Instant.ofEpochMilli(timestamp1)
                .atZone(ZoneId.systemDefault()) // 使用系统默认时区
                .toLocalDate();

        LocalDate date2 = Instant.ofEpochMilli(timestamp2)
                .atZone(ZoneId.systemDefault()) // 使用系统默认时区
                .toLocalDate();

        // 比较日期部分是否相同
        return date1.isEqual(date2);
    }

    /**
     * 获取 UTC 时区的当前日期，并返回 java.util.Date 类型
     *
     * @return java.util.Date 对象，表示 UTC 时区的当前日期
     */
    public static Date getUTCDate() {
        // 获取 UTC 时区的当前时间
        ZonedDateTime utcTime = ZonedDateTime.now(ZoneId.of("UTC"));

        // 提取 UTC 时区的日期部分
        ZonedDateTime utcDateTime = utcTime.toLocalDate().atStartOfDay(ZoneId.of("UTC"));

        // 将 ZonedDateTime 转换为 java.util.Date
        return Date.from(utcDateTime.toInstant());
    }

    /**
     * 将 LocalTime 转换为 Date
     *
     * @param localTime LocalTime对象
     * @return Date对象
     */
    public static Date convertToDate(LocalTime localTime) {
        // 使用当前日期作为参考日期
        LocalDate today = LocalDate.now();

        // 将 LocalTime 和 LocalDate 结合成 LocalDateTime
        LocalDateTime localDateTime = LocalDateTime.of(today, localTime);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String format = localDateTime.format(formatter);
        // 将 LocalDateTime 转换为 Date
        return DateUtils.parseDate(format);
    }

    /**
     * 判断是否在指定时间段内
     *
     * @param value    要判断的时间戳
     * @param minValue 开始时间戳
     * @param maxValue 结束时间戳
     * @return 是否在指定时间段内
     */
    public static boolean isBetween(Long value, Long minValue, Long maxValue) {
        return value >= minValue && value <= maxValue;
    }
}
