DateUtil

点击查看
import org.junit.Test;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.WeekFields;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Java8DateUtil {

    public static final String yyyy_MM_dd_HH_mm_ss_SSS = "yyyy-MM-dd HH:mm:ss.SSS";
    public static final String yyyy_MM_dd_HH_mm_ss = "yyyy-MM-dd HH:mm:ss";
    public static final String yyyy_MM_dd_HH_mm = "yyyy-MM-dd HH:mm";
    public static final String yyyy_MM_dd_HH_mm_ss_cn = "yyyy年MM月dd日 HH时mm分ss秒";
    public static final String yyyy_MM_dd_HH_mm_cn = "yyyy年MM月dd日 HH时mm分";
    public static final String yyyy_MM_dd = "yyyy-MM-dd";
    public static final String yyyy_MM_dd_cn = "yyyy年MM月dd日";
    public static final String HH_mm_ss = "HH:mm:ss";
    public static final String HH_mm = "HH:mm";
    public static final String HH_mm_ss_cn = "HH时mm分ss秒";

    /**
     * parse datetime
     *
     * @param datetime
     * @param formatter
     * @return
     */
    public static LocalDateTime parseLocalDateTime(String datetime, String formatter) {
        return LocalDateTime.parse(datetime, DateTimeFormatter.ofPattern(formatter));
    }

    /**
     * parse date
     *
     * @param date
     * @param formatter
     * @return
     */
    public static LocalDate parseLocalDate(String date, String formatter) {
        return LocalDate.parse(date, DateTimeFormatter.ofPattern(formatter));
    }

    /**
     * parse time
     *
     * @param time
     * @param formatter
     * @return
     */
    public static LocalTime parseLocalTime(String time, String formatter) {
        return LocalTime.parse(time, DateTimeFormatter.ofPattern(formatter));
    }

    /**
     * format datetime
     *
     * @param datetime
     * @param formatter
     * @return
     */
    public static String formatLocalDateTime(LocalDateTime datetime, String formatter) {
        return datetime.format(DateTimeFormatter.ofPattern(formatter));
    }


    /**
     * format date
     *
     * @param date
     * @param formatter
     * @return
     */
    public static String formatLocalDate(LocalDate date, String formatter) {
        return date.format(DateTimeFormatter.ofPattern(formatter));
    }


    /**
     * format time
     *
     * @param time
     * @param formatter
     * @return
     */
    public static String formatLocalTime(LocalTime time, String formatter) {
        return time.format(DateTimeFormatter.ofPattern(formatter));
    }


    /**
     * 日期相隔天数
     *
     * @param start
     * @param end
     * @return
     */
    public static long betweenDays(LocalDate start, LocalDate end) {
        return ChronoUnit.DAYS.between(start, end);
    }

    /**
     * 日期相隔小时
     *
     * @param start
     * @param end
     * @return
     */
    public static long betweenHours(LocalDateTime start, LocalDateTime end) {
        return Duration.between(start, end).toHours();
    }

    /**
     * 日期相隔分钟
     *
     * @param start
     * @param end
     * @return
     */
    public static long betweenMinutes(LocalDateTime start, LocalDateTime end) {
        return Duration.between(start, end).toMinutes();
    }

    /**
     * 日期相隔毫秒数
     *
     * @param start
     * @param end
     * @return
     */
    public static long betweenMillis(LocalDateTime start, LocalDateTime end) {
        return Duration.between(start, end).toMillis();
    }

    /**
     * LocalDate --> Date
     *
     * @param localDate
     * @return
     */
    public static Date localDate2Date(LocalDate localDate) {
        return Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * LocalDateTime --> Date
     *
     * @param localDateTime
     * @return
     */
    public static Date localDateTime2Date(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * Date --> LocalDate
     *
     * @param date
     * @return
     */
    public static LocalDate date2LocalDate(Date date) {
        return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDate();
    }

    /**
     * Date --> LocalDateTime
     *
     * @param date
     * @return
     */
    public static LocalDateTime date2LocalDateTime(Date date) {
        return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

    /**
     * timeMillis --> LocalDate
     *
     * @param timeMillis
     * @return
     */
    public static LocalDate timeMillis2LocalDate(Long timeMillis) {
        return Instant.ofEpochMilli(timeMillis).atZone(ZoneId.systemDefault()).toLocalDate();
    }

    /**
     * timeMillis --> LocalTime
     *
     * @param timeMillis
     * @return
     */
    public static LocalTime timeMillis2LocalTime(Long timeMillis) {
        return Instant.ofEpochMilli(timeMillis).atZone(ZoneId.systemDefault()).toLocalTime();
    }

    /**
     * timeMillis --> LocalDateTime
     *
     * @param timeMillis
     * @return
     */
    public static LocalDateTime timeMillis2LocalDateTime(Long timeMillis) {
        return Instant.ofEpochMilli(timeMillis).atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

    /**
     * LocalDate  --> timeMillis
     *
     * @param localDate
     * @return
     */
    public static Long localDate2timeMillis(LocalDate localDate) {
        return localDate2Date(localDate).getTime();
    }

    /**
     * LocalTime  --> timeMillis
     *
     * @param localTime
     * @return
     */
    public static Long localTime2timeMillis(LocalTime localTime) {
        return localDateTime2timeMillis(LocalDateTime.of(LocalDate.of(1970, 1, 1), localTime));
    }

    /**
     * LocalDateTime  --> timeMillis
     *
     * @param localDateTime
     * @return
     */
    public static Long localDateTime2timeMillis(LocalDateTime localDateTime) {
        return localDateTime2Date(localDateTime).getTime();
    }

    /**
     * 获取2个日期之间的所有日期(闭区间(即: 包括首尾))
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static List<LocalDate> getDatesBetween2Dates(LocalDate startDate, LocalDate endDate) {
        if (startDate.isAfter(endDate)) {
            throw new RuntimeException("开始日期不能晚于结束日期");
        }
        List<LocalDate> localDates = new ArrayList<>();
        LocalDate item = startDate;
        while (!item.isAfter(endDate)) {
            localDates.add(item);
            item = item.plusDays(1);
        }
        return localDates;
    }

    /**
     * 获取2个日期之间的所有日期(闭区间(即: 包括首尾))
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static List<LocalDate> getDatesBetween2DatesV2(LocalDate startDate, LocalDate endDate) {
        if (startDate.isAfter(endDate)) {
            throw new RuntimeException("开始日期不能晚于结束日期");
        }
        return Stream.iterate(startDate, date -> date.plusDays(1)).limit(ChronoUnit.DAYS.between(startDate, endDate) + 1).collect(Collectors.toList());
    }

    /**
     * 该日期所在月份的第一天
     *
     * @param date
     * @return
     */
    public static LocalDate getFirstDateOfMonth(LocalDate date) {
        return LocalDate.of(date.getYear(), date.getMonthValue(), 1);
    }

    /**
     * 该日期所在月份的最后一天
     *
     * @param date
     * @return
     */
    public static LocalDate getLastDateOfMonth(LocalDate date) {
        return LocalDate.of(date.getYear(), date.getMonthValue(), date.lengthOfMonth());
    }


    /**
     * 该日期所在的周在一年当中是第几周(这里的周指 ISO 标准周)
     *
     * @param date 指定日期
     * @return
     */
    public static int getWeekOfWeekBasedYear(LocalDate date) {
        /** ISO标准周: 周一为每周的第一天 */
        // 第一周: 本年度第一个至少有 4 天的周,WeekFields 源码中也是这样定义的: WeekFields ISO = new WeekFields(DayOfWeek.MONDAY, 4));
        //        至少有 4 天,换句话说就是本年度就是第一个周四所在的周;
        //        第一周和最后一周是有可能跨年的,示例: 2025年的第一周为: 2024-12-30 ~ 2025-01-05;

        /** SUNDAY_START: 周日为每周的第一天,适用于北美和部分欧洲国家 */
        // 第一周: 第一个至少有 1 天的周

        return date.get(WeekFields.ISO.weekOfWeekBasedYear());
    }

    /**
     * 该日期所在的周对应的年份(这里的周指 ISO 标准周)
     * 第一周和最后一周是有可能跨年的,示例: 2025年的第一周为: 2024-12-30 ~ 2025-01-05;因此 2024-12-30 和 2024-12-31 所在周对应的年份也是 2025
     *
     * @param date 指定日期
     * @return
     */
    public static int getWeekBasedYear(LocalDate date) {
        return date.get(WeekFields.ISO.weekBasedYear());
    }

    /**
     * 查看指定年份指定周对应的周一(这里的周指 ISO 标准周)
     *
     * @param year       示例: 2024
     * @param weekOfYear 第几周
     * @return
     */
    public static LocalDate getMondayByWeekOfYear(int year, int weekOfYear) {
        // 获取指定年份的第一天
        LocalDate firstDayOfYear = LocalDate.of(year, 1, 1);
        // 第一个周四
        LocalDate firstThursday = firstDayOfYear.with(TemporalAdjusters.nextOrSame(DayOfWeek.THURSDAY));
        // 第一个周一
        LocalDate mondayOfFirstWeek = firstThursday.minusDays(3);
        return mondayOfFirstWeek.plusWeeks(weekOfYear - 1);
    }


    /**
     * 该日期所在周的周一
     *
     * @param date
     * @return
     */
    public static LocalDate getDateOfMonday(LocalDate date) {
        return date.minusDays(date.getDayOfWeek().getValue() - 1);
    }

    /**
     * 该日期所在周的周日
     *
     * @param date
     * @return
     */
    public static LocalDate getDateOfSunday(LocalDate date) {
        return date.plusDays(7 - date.getDayOfWeek().getValue());
    }

    /**
     * 某天的 00:00:00
     *
     * @param date
     * @return
     */
    public static LocalDateTime getDayBegin(LocalDate date) {
        return LocalDateTime.of(date, LocalTime.of(0, 0, 0));
    }

    /**
     * 某天的 23:59:59
     *
     * @param date
     * @return
     */
    public static LocalDateTime getDayEnd(LocalDate date) {
        return LocalDateTime.of(date, LocalTime.of(23, 59, 59));
    }

    /**
     * 该日期所在的季度
     *
     * @param date 指定日期
     * @return 1, 2, 3, 4
     */
    public static Integer getQuarter(LocalDate date) {
        return (int) Math.ceil(LocalDate.now().getMonthValue() / 3.0);
    }

    /**
     * 格式化时间段
     *
     * @param millis 毫秒
     * @return
     */
    public static String formatDuring(long millis) {
        if (Long.valueOf(0L).equals(millis)) {
            return "0毫秒";
        }
        long days = millis / (1000 * 60 * 60 * 24);
        long left = millis % (1000 * 60 * 60 * 24);
        long hours = left / (1000 * 60 * 60);
        left = left % (1000 * 60 * 60);
        long minutes = left / (1000 * 60);
        left = left % (1000 * 60);
        long seconds = left / 1000;
        left = left % 1000;
        String s = days > 0 ? (days + "天") : ("");
        s += hours > 0 ? (hours + "小时") : ("");
        s += minutes > 0 ? (minutes + "分钟") : ("");
        s += seconds > 0 ? (seconds + "秒") : ("");
        s += left > 0 ? (left + "毫秒") : ("");
        return s;
    }

    

    // 节假日
    // https://timor.tech/api/holiday/

    @Test
    public void parseTest() {
        System.err.println(parseLocalDateTime("2020-01-01 10:10:10.100", yyyy_MM_dd_HH_mm_ss_SSS));
        System.err.println(parseLocalDateTime("2020-01-01 10:10:10", yyyy_MM_dd_HH_mm_ss));
        System.err.println(parseLocalDate("2020-01-01", yyyy_MM_dd));
        System.err.println(parseLocalTime("10:10:10", HH_mm_ss));
    }

    @Test
    public void formatTest() {
        System.err.println(formatLocalDateTime(LocalDateTime.now(), yyyy_MM_dd_HH_mm_ss_SSS));
        System.err.println(formatLocalDateTime(LocalDateTime.now(), yyyy_MM_dd_HH_mm_ss));
        System.err.println(formatLocalDate(LocalDate.now(), yyyy_MM_dd));
        System.err.println(formatLocalTime(LocalTime.now(), HH_mm_ss));
    }

    @Test
    public void betweenTest() {
        System.out.println(betweenDays(LocalDate.of(2020, 6, 1), LocalDate.of(2020, 7, 1)));
        System.out.println(betweenHours(LocalDateTime.now(), LocalDateTime.now().plusHours(100)));
        System.out.println(betweenMinutes(LocalDateTime.now(), LocalDateTime.now().plusMinutes(100)));
        System.out.println(betweenMillis(LocalDateTime.now(), LocalDateTime.now().plusHours(100)));
    }

    @Test
    public void convertTest() {
        System.err.println(localDate2Date(LocalDate.now()));
        System.err.println(localDateTime2Date(LocalDateTime.now()));
        System.err.println(date2LocalDate(new Date()));
        System.err.println(date2LocalDateTime(new Date()));
    }

    @Test
    public void millisTest() {
        System.out.println(timeMillis2LocalDate(System.currentTimeMillis()));
        System.out.println(timeMillis2LocalTime(System.currentTimeMillis()));
        System.out.println(timeMillis2LocalDateTime(System.currentTimeMillis()));

        System.err.println(localDate2timeMillis(LocalDate.now()));
        System.err.println(localTime2timeMillis(LocalTime.now()));
        System.err.println(localDateTime2timeMillis(LocalDateTime.now()));
    }

    @Test
    public void getMondayByWeekOfYearTest() {
        LocalDate secondWeekOf2024 = getMondayByWeekOfYear(2024, 2);
        LocalDate firstWeekOf2025 = getMondayByWeekOfYear(2025, 1);
        LocalDate firstWeekOf2027 = getMondayByWeekOfYear(2027, 1);
        System.err.println(secondWeekOf2024);
        System.err.println(firstWeekOf2025);
        System.err.println(firstWeekOf2027);
    }

    @Test
    public void getWeekBasedYearTest() {
        int year = getWeekBasedYear(LocalDate.of(2024, 12, 30));
        System.err.println(year);
    }

    @Test
    public void getDatesBetween2DatesTest() {
        List<LocalDate> dates = getDatesBetween2Dates(LocalDate.of(2025, 1, 1), LocalDate.of(2025, 2, 15));
        System.err.println(dates);
    }

    @Test
    public void getDatesBetween2DatesV2Test() {
        List<LocalDate> dates = getDatesBetween2DatesV2(LocalDate.of(2025, 1, 1), LocalDate.of(2025, 2, 15));
        System.err.println(dates);
    }

    /**
     * 补充:
     *
     *  mysql数据类型 - java数据类型
     *      time - LocalTime/java.sql.Time
     *      date - LocalDate/java.sql.Date
     *      datetime - LocalDateTime/java.util.Date
     *
     *  java8 日期类 和 mysql 的字段类型映射,需满足: mysql 驱动包版本不低于 4.2
     *     <dependency>
     *         <groupId>mysql</groupId>
     *         <artifactId>mysql-connector-java</artifactId>
     *         <version>5.1.37</version>
     *     </dependency>
     *
     *  如果使用 mybatis,则还需添加依赖(mybatis-plus 较新版本已经做了支持,不需要该依赖)
     *     <dependency>
     *         <groupId>org.mybatis</groupId>
     *         <artifactId>mybatis-typehandlers-jsr310</artifactId>
     *         <version>1.0.1</version>
     *     </dependency>
     *
     */

}

posted @ 2025-11-16 20:47  凛冬雪夜  阅读(12)  评论(0)    收藏  举报