前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

一、Local 日期

1、基本方法


 
LocalTime 只包括时间,mapper 对应 time
LocalDate 只包括日期,mapper 对应 date
LocalDateTime 包括日期和时间,,mapper 对应 timestamp

1)LocalTime

基本方法 结果 说明
LocalTime now = LocalTime.now() 11:09:09.240 LocalTime 包含毫秒
LocalTime now = LocalTime.now().withNano(0)); 11:09:09 清除毫秒数
LocalTime localtime = LocalTime.of(0, 0, 0); 00:00:00  
LocalTime localtime = LocalTime.parse("12:00:00"); 12:00:00 字符串截取,严格按照ISO yyyy-MM-dd验证

2)LocalDate

基本方法 说明
LocalDate today = LocalDate.now();  
LocalDate date = LocalDate.of(2017, 5, 25);  
LocalDate date = LocalDate.of(2017, 05, 25); 字符串截取,严格按照ISO yyyy-MM-dd验证
LocalDate date = LocalDate.parse("2014-02-28");  
LocalDate date = LocalDate.parse("2014-2-28"); 错误
   

3)LocalDateTime

基本方法 说明
LocalDateTime d1 = LocalDateTime.of(2013, 12, 31, 23, 59); 年,月,日,时,分
LocalDateTime d3 = LocalDateTime.of(2013, 12, 31, 23, 59,59); 年,月,日,时,分,秒
LocalDateTime d2 = LocalDateTime.of(2013, 12, 31, 23, 59,59, 11); 年,月,日,时,分,秒毫秒
   
LocalDateTime d1 = LocalDateTime.parse("2013-12-31T23:59");  
LocalDateTime d2 = LocalDateTime.parse("2013-12-31T23:59:59");  
LocalDateTime d3 = LocalDateTime.parse("2013-12-31T23:59:59.000000011");  

2、常用方法

1)获取固定的日期

方法 说明
LocalDate.now().getYear(); 年份
LocalDate.now().getMonthValue(); 月份(数值表示, 从1开始)
LocalDate.now().getMonth(); 月份(英文[enum]表示)
LocalDate.now().getDayOfMonth(); 日期(从1开始)
LocalDate.now().getDayOfYear(): 当天所在这一年的第几天(从1开始)
LocalDate.now().getDayOfWeek() 星期几
LocalDate.now().lengthOfYear(); 当年的天数
LocalDate.now().lengthOfMonth(); 当月的天数
LocalDate.now().toEpochDay(); 与时间纪元(1970年1月1日)相差的天数,负数表示在时间纪元之前多少天
LocalDateTime todayStart = now.atStartOfDay(); 当天开始时间
LocalDateTime.of(LocalDateTime.now().toLocalDate(), LocalTime.MIN) 获取当他开始时间
LocalDateTime.of(LocalDateTime.now().toLocalDate(), LocalTime.MAX) 获取当天结束时间

2)加减法

方法 说明
LocalDate.now().plusDays(1) 加1天
LocalDate.now().plusWeeks(1) 加1周
LocalDate.now().plusMonths(1) 加1月
LocalDate.now().plusYears(1) 加1年
LocalDate.now().minusDays(1) 减1天
LocalDate.now().minusWeeks(1) 减1周
LocalDate.now().minusMonths(1) 减1月
LocalDate.now().minusYears(1) 减1年
LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS); 加1周
LocalDate nextMonth = today.plus(1, ChronoUnit.MONTHS); 加1月
LocalDate nextDecade = today.plus(1, ChronoUnit.DECADES); 加1年

3)日期替换

| 方法 (当前:2019-07-17) | 说明 | 结果 | | ———————————– | ————- | ———- | | LocalDate.now().withDayOfMonth(1) | 替换日期为1 | 2019-07-01 | | ` LocalDate.now().withDayOfYear(1) | 替换天数为1 | 2019-01-01 | | LocalDate.now().withMonth(1) | 替换月份为1 | 2019-01-17 | | LocalDate.now().withYear(1)` | 替换年份为1: | 0001-07-17 |

4)比较

方法 (当天 LocalDate.now() = 2019-07-17 说明 结果
LocalDate.now().minusDays(1).isBefore(LocalDate.now()) 是否在当天之前 true
LocalDate.now().plusDays(1).isAfter(LocalDate.now()) 是否在当天之后 true
LocalDate.now().isEqual(LocalDate.now()) 是否在当天 true
LocalDate.now().isLeapYear() 今年是否是闰年 False

5)计算

建议使用ChronoUnit 更全面一些

方法 说明
int daysNum = Period.between(startTime.toLocalDate(), endTime.toLocalDate()).getDays(); 相差天数
int monthNum = Period.between(startTime.toLocalDate(), endTime.toLocalDate()).getMonths() 相差月数
   
long daysDiff = ChronoUnit.DAYS.between(startTime, endTime); 相差天数
` long monthDiff = ChronoUnit.MONTHS.between(startTime, endTime);` 相差月数
long hourDiff = ChronoUnit.HOURS.between(startTime, endTime); 相乘小时数

3、实战

1)Controller

建议用字符串做入参和出参

@Configuration
public class DateConfig {
    /***
     * 日期参数接收转换器,将json字符串转为日期类型
     * @return
     */
    @Bean
    public Converter<String, LocalDateTime> LocalDateTimeConvert() {
        return new Converter<String, LocalDateTime>() {
            @Override
            public JavaType getInputType(TypeFactory typeFactory) {
                return null;
            }

            @Override
            public JavaType getOutputType(TypeFactory typeFactory) {
                return null;
            }

            @Override
            public LocalDateTime convert(String source) {

                DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                LocalDateTime date = null;
                try {
                    date = LocalDateTime.parse((String) source,df);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return date;
            }
        };
    }

    /***
     * 日期参数接收转换器,将json字符串转为日期类型
     * @return
     */
    @Bean
    public Converter<String, LocalDate> LocalDateConvert() {
        return new Converter<String, LocalDate>() {
            @Override
            public JavaType getInputType(TypeFactory typeFactory) {
                return null;
            }

            @Override
            public JavaType getOutputType(TypeFactory typeFactory) {
                return null;
            }

            @Override
            public LocalDate convert(String source) {

                DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                LocalDate date = null;
                try {
                    date = LocalDate.parse((String) source,df);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return date;
            }
        };
    }
}

二、Date 日期

1、实战

1)DatePeriodUtils

package com.healerjean.proj.utils.date;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Stream;


/**
 * 日期区间工具,月、季度、半年 等
 *
 * @author zhangyujin
 * @date 2022/7/19  17:57.
 */
public final class DatePeriodUtils {
    public static final String YYYY_MM_dd_HH_mm_ss = "yyyy-MM-dd HH:mm:ss";
    private static final DateTimeFormatter DTF_YYYY_MM_DD = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private static final DateTimeFormatter DTF_YYYY_MM = DateTimeFormatter.ofPattern("yyyy-MM");

    /**
     * 1、获取固定一年前的起始时间
     * 2、获取当前时间所在月份的最后一天
     *
     * @param date 日期如2022-05、2022-12 、2022-12-01
     * @return DatePeriod
     */
    public static DatePeriod getBackOneYearRange(String date) {
        String[] split = date.split("-");
        int year = Integer.parseInt(split[0]);
        int month = Integer.parseInt(split[1]);
        int halfPeripd = 1;
        if (month > 6) {
            halfPeripd = 2;
        }
        int lastYear = year - 1;
        String startTime = getHalfYearDayRangeStartTime(lastYear, halfPeripd);
        String endTime = getHalfYearDayRangeEndTime(year, halfPeripd);
        return new DatePeriod(startTime, endTime);
    }

    /**
     * 获取一段期间所在的最长半年周期
     *
     * @param startDate 起始时间 2022-01
     * @param endDate   结束时间
     * @return DatePeriod
     */
    public static DatePeriod getBackOneYearRange(String startDate, String endDate) {
        String[] startSplit = startDate.split("-");
        int startYear = Integer.parseInt(startSplit[0]);
        int startMonth = Integer.parseInt(startSplit[1]);
        int startHalfPeripd = 1;
        if (startMonth > 6) {
            startHalfPeripd = 2;
        }
        String startTime = getHalfYearDayRangeStartTime(startYear, startHalfPeripd);

        String[] endSplit = endDate.split("-");
        int endYear = Integer.parseInt(endSplit[0]);
        int endMonth = Integer.parseInt(endSplit[1]);
        int endHalfPeripd = 1;
        if (endMonth > 6) {
            endHalfPeripd = 2;
        }
        String endTime = getHalfYearDayRangeEndTime(endYear, endHalfPeripd);
        return new DatePeriod(startTime, endTime);
    }


    /**
     * 获取某年某月的天数
     *
     * @param date yyyy-MM 如:2022-06
     * @return  30
     */
    public static int getMonthDay(String date) {
        String[] split = date.split("-");
        return getMonthDay(Integer.parseInt(split[0]), Integer.parseInt(split[1]));
    }

    /**
     * 获取某年某月的天数
     *
     * @param year  年
     * @param month 月份
     * @return 天数
     */
    public static int getMonthDay(int year, int month) {
        DatePeriod monthRange = getMonthDayRange(year, month);
        return (int) ChronoUnit.DAYS.between(toLocalDateTime(monthRange.getStartDateTime()), toLocalDateTime(monthRange.getEndDateTime())) + 1;
    }


    /**
     * 获取某年某季度的天数
     *
     * @param date  2022-4
     * @return 92
     */
    public static int getQuarterDay(String date) {
        String[] split = date.split("-");
        return getQuarterDay(Integer.parseInt(split[0]), Integer.parseInt(split[1]));
    }

    /**
     * 获取某年某季度的天数
     *
     * @param year    年
     * @param quarter 季度
     * @return 天数
     */
    public static int getQuarterDay(int year, int quarter) {
        DatePeriod monthRange = getQuarterDayRange(year, quarter);
        return (int) ChronoUnit.DAYS.between(toLocalDateTime(monthRange.getStartDateTime()), toLocalDateTime(monthRange.getEndDateTime())) + 1;
    }

    /**
     * 获取某半年的天数
     *
     * @param date 日期
     * @return 天数
     */
    public static int getHalfYearDay(String date) {
        String[] split = date.split("-");
        return getHalfYearDay(Integer.parseInt(split[0]), Integer.parseInt(split[1]));
    }

    /**
     * 获取某半年天数
     *
     * @param year    年
     * @param quarter 前半年或后半年
     * @return 天数
     */
    public static int getHalfYearDay(int year, int quarter) {
        DatePeriod monthRange = getHalfYearRange(year, quarter);
        return (int) ChronoUnit.DAYS.between(toLocalDateTime(monthRange.getStartDateTime()), toLocalDateTime(monthRange.getEndDateTime())) + 1;
    }


    /**
     * 计算环比月
     *
     * @param currMonth 2019-01
     * @return 2018-12
     */
    public static String getHbMonth(String currMonth) {
        currMonth = currMonth + "-01";
        LocalDate d = LocalDate.parse(currMonth, DTF_YYYY_MM_DD);
        return DTF_YYYY_MM.format(d.minusMonths(1L));
    }


    /**
     * 计算同比月
     *
     * @param currMonth 2019-01
     * @return 2018-01
     */
    public static String getTbMonth(String currMonth) {
        currMonth = currMonth + "-01";
        LocalDate d = LocalDate.parse(currMonth, DTF_YYYY_MM_DD);
        return DTF_YYYY_MM.format(d.minusYears(1L));
    }


    /**
     * 计算同比季度(去年同期)
     * date 2022-4
     *
     * @return 2021-4
     */
    public static String getTbQuarter(String date) {
        String[] dateArray = date.split("-");
        int year = Integer.parseInt(dateArray[0]) - 1;
        return year + "-" + dateArray[1];
    }


    /**
     * 计算环比季度
     *
     * @param date 2019-1
     * @return 2019-1 -> 2018-4 、 2019-2 -> 2019-1
     */
    public static String getHbQuarter(String date) {
        String[] dateArray = date.split("-");
        int quarter = Integer.parseInt(dateArray[1]) - 1;
        if (quarter > 0) {
            return dateArray[0] + "-" + quarter;
        }

        int year = Integer.parseInt(dateArray[0]) - 1;
        return year + "-" + 4;
    }


    /**
     * 计算同比 半年
     * date 2022-1
     *
     * @return 2021-1
     */
    public static String getTbHalfYear(String date) {
        String[] dateArray = date.split("-");
        int year = Integer.parseInt(dateArray[0]) - 1;
        return year + "-" + dateArray[1];
    }


    /**
     * 计算环比-半年
     * date 2022-1
     *
     * @return 2021-1
     */
    public static String getHbHalfYear(String date) {
        String[] dateArray = date.split("-");
        int num = Integer.parseInt(dateArray[1]) - 1;
        if (num > 0) {
            return dateArray[0] + "-" + num;
        }
        int year = Integer.parseInt(dateArray[0]) - 1;
        return year + "-" + 2;
    }


    /**
     * 获取半年起始和结束时间
     *
     * @param year   年
     * @param period 1 前半年 2 后半年
     * @return DatePeriod
     */
    public static DatePeriod getHalfYearRange(int year, int period) {
        LocalDate startDate, endDate;
        switch (period) {
            case 1:
                // 01.01-06.30
                startDate = LocalDate.of(year, 1, 1);
                endDate = LocalDate.of(year, 6, 30);
                break;
            case 2:
                // 07.01-12.31
                startDate = LocalDate.of(year, 7, 1);
                endDate = LocalDate.of(year, 12, 31);
                break;
            default:
                throw new RuntimeException("quarter range [1-4]");
        }
        return new DatePeriod(toDateString(startDate.atTime(LocalTime.MIN)), toDateString(endDate.atTime(LocalTime.MAX)));
    }


    /**
     * 获取某半年的起始时间
     *
     * @param year   年
     * @param period 周期 1 前半年 2 后半年
     * @return
     */
    public static String getHalfYearDayRangeStartTime(int year, int period) {
        LocalDate startDate;
        switch (period) {
            case 1:
                // 01.01-06.30
                startDate = LocalDate.of(year, 1, 1);
                break;
            case 2:
                // 07.01-12.31
                startDate = LocalDate.of(year, 7, 1);
                break;
            default:
                throw new RuntimeException("quarter range [1-4]");
        }
        return toDateString(startDate.atTime(LocalTime.MIN));
    }


    /**
     * 获取半年结束时间
     *
     * @param year   年
     * @param period 1 前半年 2 后半年
     * @return DatePeriod
     */
    public static String getHalfYearDayRangeEndTime(int year, int period) {
        LocalDate endDate;
        switch (period) {
            case 1:
                // 01.01-06.30
                endDate = LocalDate.of(year, 6, 30);
                break;
            case 2:
                // 07.01-12.31
                endDate = LocalDate.of(year, 12, 31);
                break;
            default:
                throw new RuntimeException("quarter range [1-4]");
        }
        return toDateString(endDate.atTime(LocalTime.MAX));
    }


    /**
     * 获取某年月的第一天和最后一天
     *
     * @param year  年
     * @param month 月
     * @return DatePeriod
     */
    public static DatePeriod getMonthDayRange(int year, int month) {
        LocalDate localDate = LocalDate.of(year, month, 1);
        // 获取当前月的第一天
        LocalDate startDate = localDate.with(TemporalAdjusters.firstDayOfMonth());
        // 获取当前月的最后一天
        LocalDate endDate = localDate.with(TemporalAdjusters.lastDayOfMonth());
        return new DatePeriod(toDateString(startDate.atTime(LocalTime.MIN)), toDateString(endDate.atTime(LocalTime.MAX)));
    }


    /**
     * 获取某月的第一天
     *
     * @param year  年
     * @param month 月
     * @return 某月的第一天
     */
    public static String getMonthDayRangeStartTime(int year, int month) {
        LocalDate localDate = LocalDate.of(year, month, 1);
        // 获取当前月的第一天
        LocalDate startDate = localDate.with(TemporalAdjusters.firstDayOfMonth());
        return toDateString(startDate.atTime(LocalTime.MIN));
    }

    /**
     * 获取某月的最后一天
     *
     * @param year  年
     * @param month 月
     * @return 某月的最后一天
     */
    public static String getMonthDayRangeEndTime(int year, int month) {
        LocalDate localDate = LocalDate.of(year, month, 1);
        // 获取当前月的最后一天
        LocalDate endDate = localDate.with(TemporalAdjusters.lastDayOfMonth());
        return toDateString(endDate.atTime(LocalTime.MAX));
    }



    /**
     * 获取某年某季度的第一天和最后一天
     *
     * @param year    哪一年
     * @param quarter 第几季度
     * @return DatePeriod
     */
    public static DatePeriod getQuarterDayRange(int year, int quarter) {
        LocalDate startDate, endDate;
        switch (quarter) {
            case 1:
                // 01.01-03.31
                startDate = LocalDate.of(year, 1, 1);
                endDate = LocalDate.of(year, 3, 31);
                break;
            case 2:
                // 04.01-06.30
                startDate = LocalDate.of(year, 4, 1);
                endDate = LocalDate.of(year, 6, 30);
                break;
            case 3:
                // 07.01-09.30
                startDate = LocalDate.of(year, 7, 1);
                endDate = LocalDate.of(year, 9, 30);
                break;
            case 4:
                // 10.01-12.31
                startDate = LocalDate.of(year, 10, 1);
                endDate = LocalDate.of(year, 12, 31);
                break;
            default:
                throw new RuntimeException("quarter range [1-4]");
        }
        return new DatePeriod(toDateString(startDate.atTime(LocalTime.MIN)), toDateString(endDate.atTime(LocalTime.MAX)));
    }


    /**
     * 获取包含日期所在月份的所有月
     *
     * @param startDateTime 起始时间
     * @param endDateTime   结束时间
     * @return 月份集合 如: 2022-06、2022-07
     */
    public static List<String> getMonthList(String startDateTime, String endDateTime) {
        LocalDateTime startDateTimeLocal = toLocalDateTime(startDateTime);
        LocalDateTime endDateTimeLocal = toLocalDateTime(endDateTime);

        List<String> result = Lists.newArrayList();
        long distance = ChronoUnit.MONTHS.between(startDateTimeLocal, endDateTimeLocal);
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM");
        Stream.iterate(startDateTimeLocal, d -> d.plusMonths(1)).limit(distance + 1).forEach(f -> result.add(df.format(f)));
        Collections.sort(result);
        return result;
    }

    /**
     * 获取季度集合
     *
     * @param startDateTime 起始时间
     * @param endDateTime   结束时间
     * @return 季度集合 如: 2022-01、2022-02
     */
    public static List<String> getQuarterList(String startDateTime, String endDateTime) {
        List<String> monthList = getMonthList(startDateTime, endDateTime);
        List<String> result = Lists.newArrayList();
        if (CollectionUtils.isEmpty(monthList)) {
            return result;
        }
        Set<String> monthSet = Sets.newHashSet();
        List<String> oneQuarter = Lists.newArrayList("01", "02", "03");
        List<String> twoQuarter = Lists.newArrayList("04", "05", "06");
        List<String> threeQuarter = Lists.newArrayList("07", "08", "09");
        List<String> fourQuarter = Lists.newArrayList("10", "11", "12");
        for (String month : monthList) {
            String[] split = month.split("-");
            String y = split[0];
            String p = split[1];
            if (oneQuarter.contains(p)) {
                monthSet.add(y + "-1");
            }
            if (twoQuarter.contains(p)) {
                monthSet.add(y + "-2");
            }
            if (threeQuarter.contains(p)) {
                monthSet.add(y + "-3");
            }
            if (fourQuarter.contains(p)) {
                monthSet.add(y + "-4");
            }
        }

        result.addAll(monthSet);
        Collections.sort(result);
        return result;
    }


    /**
     * 获取半年集合
     *
     * @param startDateTime 起始时间
     * @param endDateTime   结束时间
     * @return 半年集合 如: 2022-1、2022-2
     */
    public static List<String> getHalfYearList(String startDateTime, String endDateTime) {
        List<String> monthList = getMonthList(startDateTime, endDateTime);
        List<String> result = Lists.newArrayList();
        if (CollectionUtils.isEmpty(monthList)) {
            return result;
        }
        Set<String> monthSet = Sets.newHashSet();
        List<String> firstYear = Lists.newArrayList("01", "02", "03", "04", "05", "06");
        List<String> lastYear = Lists.newArrayList("07", "08", "09", "10", "11", "12");
        for (String month : monthList) {
            String[] split = month.split("-");
            String y = split[0];
            String p = split[1];
            if (firstYear.contains(p)) {
                monthSet.add(y + "-1");
            }
            if (lastYear.contains(p)) {
                monthSet.add(y + "-2");
            }
        }
        result.addAll(monthSet);
        Collections.sort(result);
        return result;
    }



    /**
     * 获取半年集合
     * @param month 2022-01
     * @return  半年集合
     */
    public static String getQuarter(String month){
        return getQuarterList(month + "-01 00:00:00", month + "-01 00:00:00").get(0);
    }


    /**
     * 获取半年集合
     * @param month 2022-01
     * @return  半年集合
     */
    public static String getHalfYear(String month){
        return getHalfYearList(month + "-01 00:00:00", month + "-01 00:00:00").get(0);
    }



    /**
     * 根据半年周期获取季度周期
     * @param halfYearList 半年周期
     * @return 季度周期
     */
    public static List<String> getQuarterList(List<String> halfYearList) {
        if (CollectionUtils.isEmpty(halfYearList)) {
            return Lists.newArrayList();
        }
        List<String> result = new ArrayList<>();
        for (String halfYear : halfYearList) {
            int y = Integer.parseInt(halfYear.split("-")[0]);
            int p = Integer.parseInt(halfYear.split("-")[1]);
            DatePeriod halfYearRange = getHalfYearRange(y, p);
            List<String> quarterList = getQuarterList(halfYearRange.getStartDateTime(), halfYearRange.getEndDateTime());
            result.addAll(quarterList);
        }
        return result;
    }

    /**
     * 根据季度周期获取月份周期
     * @param quarterList 季度周期
     * @return 月份周期
     */
    public static List<String> getMonthList(List<String> quarterList) {
        if (CollectionUtils.isEmpty(quarterList)) {
            return Lists.newArrayList();
        }
        List<String> result = new ArrayList<>();
        for (String quarter : quarterList) {
            int y = Integer.parseInt(quarter.split("-")[0]);
            int p = Integer.parseInt(quarter.split("-")[1]);
            DatePeriod halfYearRange = getQuarterDayRange(y, p);
            List<String> monthList = getMonthList(halfYearRange.getStartDateTime(), halfYearRange.getEndDateTime());
            result.addAll(monthList);
        }
        return result;
    }

    public static LocalDateTime toLocalDateTime(String dateStr) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern(YYYY_MM_dd_HH_mm_ss);
        LocalDateTime parse = LocalDateTime.parse(dateStr, df);
        return parse;
    }

    public static String toDateString(LocalDateTime localDateTime) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern(YYYY_MM_dd_HH_mm_ss);
        return df.format(localDateTime);
    }

    public static class DatePeriod implements Serializable {
        private static final long serialVersionUID = 7704935152782849727L;
        private String startDateTime;
        private String endDateTime;
        private String monthStart;
        private String monthEnd;

        public DatePeriod() {
        }

        public DatePeriod(String startDateTime, String endDateTime) {
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            LocalDateTime startLocalDateTime = LocalDateTime.parse(startDateTime, dateTimeFormatter);
            LocalDateTime endDateLocalDateTime = LocalDateTime.parse(endDateTime, dateTimeFormatter);

            DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM");
            this.startDateTime = startDateTime;
            this.endDateTime = endDateTime;
            this.monthStart = df.format(startLocalDateTime);
            this.monthEnd = df.format(endDateLocalDateTime);
        }

        public static long getSerialVersionUID() {
            return serialVersionUID;
        }

        public String getStartDateTime() {
            return startDateTime;
        }

        public void setStartDateTime(String startDateTime) {
            this.startDateTime = startDateTime;
        }

        public String getEndDateTime() {
            return endDateTime;
        }

        public void setEndDateTime(String endDateTime) {
            this.endDateTime = endDateTime;
        }

        public String getMonthStart() {
            return monthStart;
        }

        public void setMonthStart(String monthStart) {
            this.monthStart = monthStart;
        }

        public String getMonthEnd() {
            return monthEnd;
        }

        public void setMonthEnd(String monthEnd) {
            this.monthEnd = monthEnd;
        }
    }


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

    /**
     * 获取两个日期之间的所有日期
     *
     * @param pattern   日期格式
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return Set<String>
     */
    public static List<String> getDates(String pattern, Date startDate, Date endDate) {
        List<String> result = new ArrayList<>();
        Calendar startCalendar = Calendar.getInstance();
        Calendar endCalendar = Calendar.getInstance();
        SimpleDateFormat df = new SimpleDateFormat(pattern);
        startCalendar.setTime(startDate);
        endCalendar.setTime(endDate);
        result.add(df.format(startCalendar.getTime()));
        while (true) {
            startCalendar.add(Calendar.DAY_OF_MONTH, 1);
            if (startCalendar.getTimeInMillis() <= endCalendar.getTimeInMillis()) {
                result.add(df.format(startCalendar.getTime()));
            } else {
                break;
            }
        }
        return result;
    }

}

2、问题报备

1)Calendar.DAY_OF_MONTHCalendar.DAY_OF_YEARCalendar.DATE

cal1.add(Calendar.DAY_OF_MONTH,1);  
cal1.add(Calendar.DAY_OF_YEAR,1);  
cal1.add(Calendar.DATE,1); 

⬤ 以上执行结果是一样的,但是一般情况下加减运算我们使用 cal1.add(Calendar.DATE,1);

⬤ 而其他两种的主要作用是用来获取数据的

Calendar.DAY_OF_YEAR 的主要作用是 cal.get(Calendar.DAY_OF_YEAR),用来获得这一天在是这个月的第多少天

Calendar.DAY_OF_YEAR 的主要作用是 cal.get(Calendar.DAY_OF_YEAR),用来获得这一天在是这个年的第多少天

3、工具类

package com.healerjean.proj.utils.date;

import com.google.common.collect.Lists;

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

import static com.healerjean.proj.utils.date.DateUtils.TimeTool.toLocalDateTime;

/**
 * DateUtils
 *
 * @author zhangyujin
 * @date 2023/6/14  16:06
 */
public class DateUtils {

    public static class TimeTool {

        /**
         * toDateString
         *
         * @param localDate localDate
         * @return String
         */
        public static String toDateString(LocalDate localDate) {
            return toDateString(localDate, DateConstants.YYYY_MM_DD);
        }

        /**
         * toDateString
         *
         * @param localDate localDate
         * @param format    format
         * @return String
         */
        public static String toDateString(LocalDate localDate, String format) {
            return Optional.ofNullable(localDate).map(item -> DateTimeFormatter.ofPattern(format).format(item)).orElse(null);
        }

        /**
         * toDateString
         *
         * @param localDateTime localDateTime
         * @return String
         */
        public static String toDateString(LocalDateTime localDateTime) {
            return toDateString(localDateTime, DateConstants.YYYY_MM_DD_HH_MM_SS);
        }


        /**
         * toDateString
         *
         * @param localDateTime localDateTime
         * @param format        format
         * @return String
         */
        public static String toDateString(LocalDateTime localDateTime, String format) {
            return Optional.ofNullable(localDateTime).map(item -> item.format(DateTimeFormatter.ofPattern(format))).orElse(null);
        }


        /**
         * toLocalDate
         *
         * @param dateStr dateStr
         * @return LocalDate
         */
        public static LocalDate toLocalDate(String dateStr) {
            return toLocalDate(dateStr, DateConstants.YYYY_MM_DD);
        }


        /**
         * toLocalDate
         *
         * @param dateStr dateStr
         * @param format  format
         * @return LocalDate
         */
        public static LocalDate toLocalDate(String dateStr, String format) {
            return Optional.ofNullable(dateStr).map(item -> LocalDate.parse(item, DateTimeFormatter.ofPattern(format))).orElse(null);
        }

        /**
         * toLocalDate
         *
         * @param date date
         * @return LocalDate
         */
        public static LocalDate toLocalDate(Date date) {
            return Optional.ofNullable(date).map(item -> item.toInstant().atZone(ZoneId.systemDefault()).toLocalDate()).orElse(null);
        }

        /**
         * LocalDateTime
         *
         * @param dateStr dateStr
         * @return toLocalDateTime
         */
        public static LocalDateTime toLocalDateTime(String dateStr) {
            return toLocalDateTime(dateStr, DateConstants.YYYY_MM_DD_HH_MM_SS);
        }


        /**
         * LocalDateTime
         *
         * @param dateStr dateStr
         * @param format  format
         * @return toLocalDateTime
         */
        public static LocalDateTime toLocalDateTime(String dateStr, String format) {
            return Optional.ofNullable(dateStr).map(item -> LocalDateTime.parse(item, DateTimeFormatter.ofPattern(format))).orElse(null);
        }

        /**
         * toLocalDateTime
         *
         * @param date date
         * @return LocalDateTime
         */
        public static LocalDateTime toLocalDateTime(Date date) {
            return Optional.ofNullable(date).map(item -> item.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()).orElse(null);
        }


        /**
         * toDate
         *
         * @param localDateTime localDateTime
         * @return Date
         */
        public static Date toDate(LocalDateTime localDateTime) {
            return Optional.ofNullable(localDateTime).map(item -> Date.from(item.atZone(ZoneId.systemDefault()).toInstant())).orElse(null);
        }

        /**
         * toDate
         *
         * @param localDate localDate
         * @return Date
         */
        public static Date toDate(LocalDate localDate) {
            return Optional.ofNullable(localDate).map(item -> Date.from(item.atStartOfDay(ZoneId.systemDefault()).toInstant())).orElse(null);
        }

    }


    public static class TimeExtTool {



        /**
         * 获取开始时间
         *
         * @param localDateTime localDateTime
         * @return LocalDateTime
         */
        public static LocalDateTime getFirstTime(LocalDateTime localDateTime, ChronoUnit chronoUnit) {
            switch (chronoUnit) {
                case MINUTES:
                    return localDateTime.withSecond(0).withNano(0);
                case HOURS:
                    return localDateTime.withMinute(0).withSecond(0).withNano(0);
                case DAYS:
                    return localDateTime.withHour(0).withMinute(0).withSecond(0).withNano(0);
                case MONTHS:
                    return localDateTime.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
                case YEARS:
                    return localDateTime.withDayOfYear(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
                default:
                    throw new IllegalArgumentException("field 无日期匹配类型");
            }
        }

        /**
         * 获取结束时间
         *
         * @param localDateTime localDateTime
         * @return LocalDateTime
         */
        public static LocalDateTime getEndTime(LocalDateTime localDateTime, ChronoUnit chronoUnit) {
            switch (chronoUnit) {
                case MINUTES:
                    return localDateTime.withSecond(59).withNano(0);
                case HOURS:
                    return localDateTime.withMinute(59).withSecond(59).withNano(0);
                case DAYS:
                    return localDateTime.withHour(23).withMinute(59).withSecond(59).withNano(0);
                case MONTHS:
                    return localDateTime.withDayOfMonth(localDateTime.getMonth().length(Year.isLeap(localDateTime.getYear()))).withHour(23).withMinute(59).withSecond(59).withNano(0);
                case YEARS:
                    return localDateTime.with(TemporalAdjusters.lastDayOfYear()).with(LocalTime.MAX);
                default:
                    throw new IllegalArgumentException("field 无日期匹配类型");
            }
        }

        /**
         * roll
         *
         * @param localDateTime localDateTime
         * @param field         field
         * @param num           num
         * @return {@link LocalDateTime}
         */
        public static LocalDateTime minusRoll(LocalDateTime localDateTime, ChronoUnit field, int num) {
            return localDateTime.minus(num, field);
        }


        /**
         * roll
         *
         * @param localDateTime localDateTime
         * @param field         field
         * @param num           num
         * @return {@link LocalDateTime}
         */
        public static LocalDateTime plusRoll(LocalDateTime localDateTime, ChronoUnit field, int num) {
            return localDateTime.plus(num, field);
        }

        /**
         * 获取包含日期所在月份的所有月
         *
         * @param startDateTime 起始时间
         * @param endDateTime   结束时间
         * @return 月份集合 如: 2022-06、2022-07
         */
        public static List<String> getDates(String startDateTime, String endDateTime, ChronoUnit chronoUnit, String format) {
            LocalDateTime startDateTimeLocal = toLocalDateTime(startDateTime);
            LocalDateTime endDateTimeLocal = toLocalDateTime(endDateTime);
            List<String> result = Lists.newArrayList();
            long distance = chronoUnit.between(startDateTimeLocal, endDateTimeLocal);
            DateTimeFormatter df = DateTimeFormatter.ofPattern(format);
            switch (chronoUnit) {
                case MINUTES:
                    Stream.iterate(startDateTimeLocal, d -> d.plusMinutes(1)).limit(distance + 1).forEach(f -> result.add(df.format(f)));
                    break;
                case HOURS:
                   Stream.iterate(startDateTimeLocal, d -> d.plusHours(1)).limit(distance + 1).forEach(f -> result.add(df.format(f)));
                    break;
                case DAYS:
                    Stream.iterate(startDateTimeLocal, d -> d.plusDays(1)).limit(distance + 1).forEach(f -> result.add(df.format(f)));
                    break;
                case MONTHS:
                    Stream.iterate(startDateTimeLocal, d -> d.plusMonths(1)).limit(distance + 1).forEach(f -> result.add(df.format(f)));
                    break;
                case YEARS:
                    Stream.iterate(startDateTimeLocal, d -> d.plusYears(1)).limit(distance + 1).forEach(f -> result.add(df.format(f)));
                    break;
                default:
                    throw new IllegalArgumentException("field 无日期匹配类型");
            }
            Collections.sort(result);
            return result;
        }


        public static void main(String[] args) {
            // TimeExtTool.getFirstTime
            LocalDateTime dateTime = LocalDateTime.of(2023, 10, 23, 20, 23, 21); // 示例日期时间
            System.out.println("TimeExtTool.getFirstTime" + DateUtils.TimeTool.toDateString(dateTime));
            System.out.println(DateUtils.TimeTool.toDateString(getFirstTime(dateTime, ChronoUnit.MINUTES)));
            System.out.println(DateUtils.TimeTool.toDateString(getFirstTime(dateTime, ChronoUnit.HOURS)));
            System.out.println(DateUtils.TimeTool.toDateString(getFirstTime(dateTime, ChronoUnit.DAYS)));
            System.out.println(DateUtils.TimeTool.toDateString(getFirstTime(dateTime, ChronoUnit.MONTHS)));
            System.out.println(DateUtils.TimeTool.toDateString(getFirstTime(dateTime, ChronoUnit.YEARS)));
            System.out.println();
            System.out.println("TimeExtTool.getFirstTime" + DateUtils.TimeTool.toDateString(dateTime));
            System.out.println(DateUtils.TimeTool.toDateString(dateTime));
            System.out.println(DateUtils.TimeTool.toDateString(getEndTime(dateTime, ChronoUnit.MINUTES)));
            System.out.println(DateUtils.TimeTool.toDateString(getEndTime(dateTime, ChronoUnit.HOURS)));
            System.out.println(DateUtils.TimeTool.toDateString(getEndTime(dateTime, ChronoUnit.DAYS)));
            System.out.println(DateUtils.TimeTool.toDateString(getEndTime(dateTime, ChronoUnit.MONTHS)));
            System.out.println(DateUtils.TimeTool.toDateString(getEndTime(dateTime, ChronoUnit.YEARS)));
            System.out.println();
            System.out.println("TimeExtTool.minusRoll" + DateUtils.TimeTool.toDateString(dateTime));
            System.out.println(DateUtils.TimeTool.toDateString(minusRoll(dateTime, ChronoUnit.DAYS, 1)));
            System.out.println();
            System.out.println("TimeExtTool.plusRoll" + DateUtils.TimeTool.toDateString(dateTime));
            System.out.println(DateUtils.TimeTool.toDateString(plusRoll(dateTime, ChronoUnit.DAYS, 1)));

            System.out.println();
            System.out.println("TimeExtTool.getDates" + DateUtils.TimeTool.toDateString(dateTime));
            LocalDateTime startDate = LocalDateTime.of(2023, 10, 23, 20, 23, 21); // 示例日期时间
            LocalDateTime endDate = LocalDateTime.of(2023, 11, 23, 20, 23, 21); // 示例日期时间
            System.out.println(getDates(TimeTool.toDateString(startDate), TimeTool.toDateString(endDate), ChronoUnit.DAYS, DateConstants.YYYY_MM_DD));
            System.out.println(getDates(TimeTool.toDateString(startDate), TimeTool.toDateString(endDate), ChronoUnit.MONTHS, DateConstants.YYYY_MM));
        }

    }


    public static class DateTool {

        /**
         * toDateString
         *
         * @param date    date
         * @param pattern pattern
         * @return {@link String}
         */
        public static String toDateString(Date date, String pattern) {
            SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
            return dateFormat.format(date);
        }


        /**
         * toDate
         *
         * @param dateStr dateStr
         * @param pattern pattern
         * @return {@link Date}
         */
        public static Date toDate(String dateStr, String pattern) {
            SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
            try {
                return dateFormat.parse(dateStr);
            } catch (ParseException e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        }


        /**
         * longToDate
         *
         * @param longDate longDate
         * @return {@link Date}
         */
        public static Date longToDate(Long longDate) {
            if (longDate == null) {
                return null;
            }
            return new Date(longDate);
        }

    }


    public static class DateExtTool {

        /**
         * getFirstTime
         *
         * @return Date
         */
        public static Date getFirstTime(Date date, int field) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            switch (field) {
                //1、获取小时的最初时间
                case Calendar.HOUR:
                    cal.set(Calendar.MINUTE, 0);
                    cal.set(Calendar.SECOND, 0);
                    cal.set(Calendar.MILLISECOND, 0);
                    return cal.getTime();
                case Calendar.DATE:
                    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();
                case Calendar.MONTH:
                    cal.set(Calendar.DAY_OF_MONTH, cal.getActualMinimum(Calendar.DAY_OF_MONTH));
                    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();
                case Calendar.YEAR:
                    cal.set(Calendar.MONTH, Calendar.JANUARY);
                    cal.set(Calendar.DAY_OF_YEAR, cal.getActualMinimum(Calendar.DAY_OF_YEAR));
                    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();
                default:
                    throw new RuntimeException("field 无日期匹配类型");
            }
        }


        /**
         * getEndTime
         *
         * @return Date
         */
        public static Date getEndTime(Date date, int field) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            switch (field) {
                //1、获取小时的最后时间
                case Calendar.HOUR:
                    cal.set(Calendar.MINUTE, 59);
                    cal.set(Calendar.SECOND, 59);
                    cal.set(Calendar.MILLISECOND, 0);
                    return cal.getTime();
                case Calendar.DATE:
                    cal.set(Calendar.HOUR_OF_DAY, 23);
                    cal.set(Calendar.MINUTE, 59);
                    cal.set(Calendar.SECOND, 59);
                    cal.set(Calendar.MILLISECOND, 0);
                    return cal.getTime();
                case Calendar.MONTH:
                    cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
                    cal.set(Calendar.HOUR_OF_DAY, 23);
                    cal.set(Calendar.MINUTE, 59);
                    cal.set(Calendar.SECOND, 59);
                    cal.set(Calendar.MILLISECOND, 0);
                    return cal.getTime();
                case Calendar.YEAR:
                    cal.set(Calendar.MONTH, Calendar.DECEMBER);
                    cal.set(Calendar.DAY_OF_YEAR, cal.getActualMaximum(Calendar.DAY_OF_YEAR));
                    cal.set(Calendar.HOUR_OF_DAY, 23);
                    cal.set(Calendar.MINUTE, 59);
                    cal.set(Calendar.SECOND, 59);
                    cal.set(Calendar.MILLISECOND, 0);
                    return cal.getTime();
                default:
                    throw new RuntimeException("field 无日期匹配类型");
            }
        }


        /**
         * roll
         *
         * @param date date
         * @param field field
         * @param num num
         * @return {@link Date}
         */
        public static Date roll(Date date, int field, int num) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            cal.add(field, num);
            return cal.getTime();
        }


    }
}

ContactAuthor