疯狂的狮子Li
2024-12-12 29c5ff89babf045035478b66961ca8c117375f5d
update 优化 重构DateUtils工具类 更加实用
已添加1个文件
已修改1个文件
396 ■■■■ 文件已修改
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/FormatsType.java 146 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java 250 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/FormatsType.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,146 @@
package org.dromara.common.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.dromara.common.core.utils.StringUtils;
/*
 * æ—¥æœŸæ ¼å¼
 * "yyyy":4位数的年份,例如:2023年表示为"2023"。
 * "yy":2位数的年份,例如:2023年表示为"23"。
 * "MM":2位数的月份,取值范围为01到12,例如:7月表示为"07"。
 * "M":不带前导零的月份,取值范围为1到12,例如:7月表示为"7"。
 * "dd":2位数的日期,取值范围为01到31,例如:22日表示为"22"。
 * "d":不带前导零的日期,取值范围为1到31,例如:22日表示为"22"。
 * "EEEE":星期的全名,例如:星期三表示为"Wednesday"。
 * "E":星期的缩写,例如:星期三表示为"Wed"。
 * "DDD" æˆ– "D":一年中的第几天,取值范围为001到366,例如:第200天表示为"200"。
 * æ—¶é—´æ ¼å¼
 * "HH":24小时制的小时数,取值范围为00到23,例如:下午5点表示为"17"。
 * "hh":12小时制的小时数,取值范围为01到12,例如:下午5点表示为"05"。
 * "mm":分钟数,取值范围为00到59,例如:30分钟表示为"30"。
 * "ss":秒数,取值范围为00到59,例如:45秒表示为"45"。
 * "SSS":毫秒数,取值范围为000到999,例如:123毫秒表示为"123"。
 */
/**
 * æ—¥æœŸæ ¼å¼ä¸Žæ—¶é—´æ ¼å¼æžšä¸¾
 */
@Getter
@AllArgsConstructor
public enum FormatsType {
    /**
     * ä¾‹å¦‚:2023年表示为"23"
     */
    YY("yy"),
    /**
     * ä¾‹å¦‚:2023年表示为"2023"
     */
    YYYY("yyyy"),
    /**
     * ä¾‹ä¾‹å¦‚,2023å¹´7月可以表示为 "2023-07"
     */
    YYYY_MM("yyyy-MM"),
    /**
     * ä¾‹å¦‚,日期 "2023å¹´7月22日" å¯ä»¥è¡¨ç¤ºä¸º "2023-07-22"
     */
    YYYY_MM_DD("yyyy-MM-dd"),
    /**
     * ä¾‹å¦‚,当前时间如果是 "2023å¹´7月22日下午3点30分",则可以表示为 "2023-07-22 15:30"
     */
    YYYY_MM_DD_HH_MM("yyyy-MM-dd HH:mm"),
    /**
     * ä¾‹å¦‚,当前时间如果是 "2023å¹´7月22日下午3点30分45秒",则可以表示为 "2023-07-22 15:30:45"
     */
    YYYY_MM_DD_HH_MM_SS("yyyy-MM-dd HH:mm:ss"),
    /**
     * ä¾‹å¦‚:下午3点30分45秒,表示为 "15:30:45"
     */
    HH_MM_SS("HH:mm:ss"),
    /**
     * ä¾‹ä¾‹å¦‚,2023å¹´7月可以表示为 "2023/07"
     */
    YYYY_MM_SLASH("yyyy/MM"),
    /**
     * ä¾‹å¦‚,日期 "2023å¹´7月22日" å¯ä»¥è¡¨ç¤ºä¸º "2023/07/22"
     */
    YYYY_MM_DD_SLASH("yyyy/MM/dd"),
    /**
     * ä¾‹å¦‚,当前时间如果是 "2023å¹´7月22日下午3点30分45秒",则可以表示为 "2023/07/22 15:30:45"
     */
    YYYY_MM_DD_HH_MM_SLASH("yyyy/MM/dd HH:mm"),
    /**
     * ä¾‹å¦‚,当前时间如果是 "2023å¹´7月22日下午3点30分45秒",则可以表示为 "2023/07/22 15:30:45"
     */
    YYYY_MM_DD_HH_MM_SS_SLASH("yyyy/MM/dd HH:mm:ss"),
    /**
     * ä¾‹ä¾‹å¦‚,2023å¹´7月可以表示为 "2023.07"
     */
    YYYY_MM_DOT("yyyy.MM"),
    /**
     * ä¾‹å¦‚,日期 "2023å¹´7月22日" å¯ä»¥è¡¨ç¤ºä¸º "2023.07.22"
     */
    YYYY_MM_DD_DOT("yyyy.MM.dd"),
    /**
     * ä¾‹å¦‚,当前时间如果是 "2023å¹´7月22日下午3点30分",则可以表示为 "2023.07.22 15:30"
     */
    YYYY_MM_DD_HH_MM_DOT("yyyy.MM.dd HH:mm"),
    /**
     * ä¾‹å¦‚,当前时间如果是 "2023å¹´7月22日下午3点30分45秒",则可以表示为 "2023.07.22 15:30:45"
     */
    YYYY_MM_DD_HH_MM_SS_DOT("yyyy.MM.dd HH:mm:ss"),
    /**
     * ä¾‹å¦‚,2023å¹´7月可以表示为 "202307"
     */
    YYYYMM("yyyyMM"),
    /**
     * ä¾‹å¦‚,2023å¹´7月22日可以表示为 "20230722"
     */
    YYYYMMDD("yyyyMMdd"),
    /**
     * ä¾‹å¦‚,2023å¹´7月22日下午3点可以表示为 "2023072215"
     */
    YYYYMMDDHH("yyyyMMddHH"),
    /**
     * ä¾‹å¦‚,2023å¹´7月22日下午3点30分可以表示为 "202307221530"
     */
    YYYYMMDDHHMM("yyyyMMddHHmm"),
    /**
     * ä¾‹å¦‚,2023å¹´7月22日下午3点30分45秒可以表示为 "20230722153045"
     */
    YYYYMMDDHHMMSS("yyyyMMddHHmmss");
    /**
     * æ—¶é—´æ ¼å¼
     */
    private final String timeFormat;
    public static FormatsType getFormatsType(String str) {
        for (FormatsType value : values()) {
            if (StringUtils.contains(str, value.getTimeFormat())) {
                return value;
            }
        }
        throw new RuntimeException("'FormatsType' not found By " + str);
    }
}
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java
@@ -3,16 +3,15 @@
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.dromara.common.core.enums.FormatsType;
import org.dromara.common.core.exception.ServiceException;
import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.*;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
 * æ—¶é—´å·¥å…·ç±»
@@ -21,86 +20,137 @@
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
    public static final String YYYY = "yyyy";
    public static final String YYYY_MM = "yyyy-MM";
    public static final String YYYY_MM_DD = "yyyy-MM-dd";
    public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
    public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
    private static final String[] PARSE_PATTERNS = {
        "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"};
    /**
     * èŽ·å–å½“å‰Date型日期
     * èŽ·å–å½“å‰æ—¥æœŸå’Œæ—¶é—´
     *
     * @return Date() å½“前日期
     * @return å½“前日期和时间的 Date å¯¹è±¡è¡¨ç¤º
     */
    public static Date getNowDate() {
        return new Date();
    }
    /**
     * èŽ·å–å½“å‰æ—¥æœŸ, é»˜è®¤æ ¼å¼ä¸ºyyyy-MM-dd
     * èŽ·å–å½“å‰æ—¥æœŸçš„å­—ç¬¦ä¸²è¡¨ç¤ºï¼Œæ ¼å¼ä¸ºYYYY-MM-DD
     *
     * @return String
     * @return å½“前日期的字符串表示
     */
    public static String getDate() {
        return dateTimeNow(YYYY_MM_DD);
        return dateTimeNow(FormatsType.YYYY_MM_DD);
    }
    /**
     * èŽ·å–å½“å‰æ—¥æœŸçš„å­—ç¬¦ä¸²è¡¨ç¤ºï¼Œæ ¼å¼ä¸ºyyyyMMdd
     *
     * @return å½“前日期的字符串表示
     */
    public static String getCurrentDate() {
        return DateFormatUtils.format(new Date(), FormatsType.YYYYMMDD.getTimeFormat());
    }
    /**
     * èŽ·å–å½“å‰æ—¥æœŸçš„è·¯å¾„æ ¼å¼å­—ç¬¦ä¸²ï¼Œæ ¼å¼ä¸º"yyyy/MM/dd"
     *
     * @return å½“前日期的路径格式字符串
     */
    public static String datePath() {
        Date now = new Date();
        return DateFormatUtils.format(now, FormatsType.YYYY_MM_DD_SLASH.getTimeFormat());
    }
    /**
     * èŽ·å–å½“å‰æ—¶é—´çš„å­—ç¬¦ä¸²è¡¨ç¤ºï¼Œæ ¼å¼ä¸ºYYYY-MM-DD HH:MM:SS
     *
     * @return å½“前时间的字符串表示
     */
    public static String getTime() {
        return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
        return dateTimeNow(FormatsType.YYYY_MM_DD_HH_MM_SS);
    }
    /**
     * èŽ·å–å½“å‰æ—¶é—´çš„å­—ç¬¦ä¸²è¡¨ç¤ºï¼Œæ ¼å¼ä¸º "HH:MM:SS"
     *
     * @return å½“前时间的字符串表示,格式为 "HH:MM:SS"
     */
    public static String getTimeWithHourMinuteSecond() {
        return dateTimeNow(FormatsType.HH_MM_SS);
    }
    /**
     * èŽ·å–å½“å‰æ—¥æœŸå’Œæ—¶é—´çš„å­—ç¬¦ä¸²è¡¨ç¤ºï¼Œæ ¼å¼ä¸ºYYYYMMDDHHMMSS
     *
     * @return å½“前日期和时间的字符串表示
     */
    public static String dateTimeNow() {
        return dateTimeNow(YYYYMMDDHHMMSS);
        return dateTimeNow(FormatsType.YYYYMMDDHHMMSS);
    }
    public static String dateTimeNow(final String format) {
    /**
     * èŽ·å–å½“å‰æ—¥æœŸå’Œæ—¶é—´çš„æŒ‡å®šæ ¼å¼çš„å­—ç¬¦ä¸²è¡¨ç¤º
     *
     * @param format æ—¥æœŸæ—¶é—´æ ¼å¼ï¼Œä¾‹å¦‚"YYYY-MM-DD HH:MM:SS"
     * @return å½“前日期和时间的字符串表示
     */
    public static String dateTimeNow(final FormatsType format) {
        return parseDateToStr(format, new Date());
    }
    public static String dateTime(final Date date) {
        return parseDateToStr(YYYY_MM_DD, date);
    /**
     * å°†æŒ‡å®šæ—¥æœŸæ ¼å¼åŒ–为 YYYY-MM-DD æ ¼å¼çš„字符串
     *
     * @param date è¦æ ¼å¼åŒ–的日期对象
     * @return æ ¼å¼åŒ–后的日期字符串
     */
    public static String formatDate(final Date date) {
        return parseDateToStr(FormatsType.YYYY_MM_DD, date);
    }
    public static String parseDateToStr(final String format, final Date date) {
        return new SimpleDateFormat(format).format(date);
    /**
     * å°†æŒ‡å®šæ—¥æœŸæ ¼å¼åŒ–为 YYYY-MM-DD HH:MM:SS æ ¼å¼çš„字符串
     *
     * @param date è¦æ ¼å¼åŒ–的日期对象
     * @return æ ¼å¼åŒ–后的日期时间字符串
     */
    public static String formatDateTime(final Date date) {
        return parseDateToStr(FormatsType.YYYY_MM_DD_HH_MM_SS, date);
    }
    public static Date dateTime(final String format, final String ts) {
    /**
     * å°†æŒ‡å®šæ—¥æœŸæŒ‰ç…§æŒ‡å®šæ ¼å¼è¿›è¡Œæ ¼å¼åŒ–
     *
     * @param format è¦ä½¿ç”¨çš„æ—¥æœŸæ—¶é—´æ ¼å¼ï¼Œä¾‹å¦‚"YYYY-MM-DD HH:MM:SS"
     * @param date   è¦æ ¼å¼åŒ–的日期对象
     * @return æ ¼å¼åŒ–后的日期时间字符串
     */
    public static String parseDateToStr(final FormatsType format, final Date date) {
        return new SimpleDateFormat(format.getTimeFormat()).format(date);
    }
    /**
     * å°†æŒ‡å®šæ ¼å¼çš„æ—¥æœŸæ—¶é—´å­—符串转换为 Date å¯¹è±¡
     *
     * @param format è¦è§£æžçš„æ—¥æœŸæ—¶é—´æ ¼å¼ï¼Œä¾‹å¦‚"YYYY-MM-DD HH:MM:SS"
     * @param ts     è¦è§£æžçš„æ—¥æœŸæ—¶é—´å­—符串
     * @return è§£æžåŽçš„ Date å¯¹è±¡
     * @throws RuntimeException å¦‚果解析过程中发生异常
     */
    public static Date parseDateTime(final FormatsType format, final String ts) {
        try {
            return new SimpleDateFormat(format).parse(ts);
            return new SimpleDateFormat(format.getTimeFormat()).parse(ts);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * æ—¥æœŸè·¯å¾„ å³å¹´/月/日 å¦‚2018/08/08
     */
    public static String datePath() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyy/MM/dd");
    }
    /**
     * æ—¥æœŸè·¯å¾„ å³å¹´/月/日 å¦‚20180808
     */
    public static String dateTime() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyyMMdd");
    }
    /**
     * æ—¥æœŸåž‹å­—符串转化为日期 æ ¼å¼
     * å°†å¯¹è±¡è½¬æ¢ä¸ºæ—¥æœŸå¯¹è±¡
     *
     * @param str è¦è½¬æ¢çš„对象,通常是字符串
     * @return è½¬æ¢åŽçš„æ—¥æœŸå¯¹è±¡ï¼Œå¦‚果转换失败或输入为null,则返回null
     */
    public static Date parseDate(Object str) {
        if (str == null) {
@@ -115,6 +165,8 @@
    /**
     * èŽ·å–æœåŠ¡å™¨å¯åŠ¨æ—¶é—´
     *
     * @return æœåŠ¡å™¨å¯åŠ¨æ—¶é—´çš„ Date å¯¹è±¡è¡¨ç¤º
     */
    public static Date getServerStartDate() {
        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
@@ -122,35 +174,66 @@
    }
    /**
     * è®¡ç®—相差天数
     * è®¡ç®—两个日期之间的天数差(以毫秒为单位)
     *
     * @param date1 ç¬¬ä¸€ä¸ªæ—¥æœŸ
     * @param date2 ç¬¬äºŒä¸ªæ—¥æœŸ
     * @return ä¸¤ä¸ªæ—¥æœŸä¹‹é—´çš„天数差的绝对值
     */
    public static int differentDaysByMillisecond(Date date1, Date date2) {
        return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
    }
    /**
     * è®¡ç®—两个时间差
     * è®¡ç®—两个日期之间的时间差,并以天、小时和分钟的格式返回
     *
     * @param endDate ç»“束日期
     * @param nowDate å½“前日期
     * @return è¡¨ç¤ºæ—¶é—´å·®çš„字符串,格式为"天 å°æ—¶ åˆ†é’Ÿ"
     */
    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 + "分钟";
        long diffInMillis = endDate.getTime() - nowDate.getTime();
        long day = TimeUnit.MILLISECONDS.toDays(diffInMillis);
        long hour = TimeUnit.MILLISECONDS.toHours(diffInMillis) % 24;
        long min = TimeUnit.MILLISECONDS.toMinutes(diffInMillis) % 60;
        return String.format("%d天 %d小时 %d分钟", day, hour, min);
    }
    /**
     * å¢žåŠ  LocalDateTime ==> Date
     * è®¡ç®—两个时间点的差值(天、小时、分钟、秒),当值为0时不显示该单位
     *
     * @param endDate ç»“束时间
     * @param nowDate å½“前时间
     * @return æ—¶é—´å·®å­—符串,格式为 "x天 x小时 x分钟 x秒",若为 0 åˆ™ä¸æ˜¾ç¤º
     */
    public static String getTimeDifference(Date endDate, Date nowDate) {
        long diffInMillis = endDate.getTime() - nowDate.getTime();
        long day = TimeUnit.MILLISECONDS.toDays(diffInMillis);
        long hour = TimeUnit.MILLISECONDS.toHours(diffInMillis) % 24;
        long min = TimeUnit.MILLISECONDS.toMinutes(diffInMillis) % 60;
        long sec = TimeUnit.MILLISECONDS.toSeconds(diffInMillis) % 60;
        // æž„建时间差字符串,条件是值不为0才显示
        StringBuilder result = new StringBuilder();
        if (day > 0) {
            result.append(String.format("%d天 ", day));
        }
        if (hour > 0) {
            result.append(String.format("%d小时 ", hour));
        }
        if (min > 0) {
            result.append(String.format("%d分钟 ", min));
        }
        if (sec > 0) {
            result.append(String.format("%d秒", sec));
        }
        return result.length() > 0 ? result.toString().trim() : "0秒";
    }
    /**
     * å°† LocalDateTime å¯¹è±¡è½¬æ¢ä¸º Date å¯¹è±¡
     *
     * @param temporalAccessor è¦è½¬æ¢çš„ LocalDateTime å¯¹è±¡
     * @return è½¬æ¢åŽçš„ Date å¯¹è±¡
     */
    public static Date toDate(LocalDateTime temporalAccessor) {
        ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
@@ -158,11 +241,46 @@
    }
    /**
     * å¢žåŠ  LocalDate ==> Date
     * å°† LocalDate å¯¹è±¡è½¬æ¢ä¸º Date å¯¹è±¡
     *
     * @param temporalAccessor è¦è½¬æ¢çš„ LocalDate å¯¹è±¡
     * @return è½¬æ¢åŽçš„ 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 startDate å¼€å§‹æ—¥æœŸ
     * @param endDate   ç»“束日期
     * @param maxValue  æœ€å¤§æ—¶é—´è·¨åº¦çš„限制值
     * @param unit      æ—¶é—´è·¨åº¦çš„单位,可选择 "DAYS"、"HOURS" æˆ– "MINUTES"
     */
    public static void validateDateRange(Date startDate, Date endDate, int maxValue, TimeUnit unit) {
        // æ ¡éªŒç»“束日期不能早于开始日期
        if (endDate.before(startDate)) {
            throw new ServiceException("结束日期不能早于开始日期");
        }
        // è®¡ç®—时间跨度
        long diffInMillis = endDate.getTime() - startDate.getTime();
        // æ ¹æ®å•位转换时间跨度
        long diff = switch (unit) {
            case DAYS -> TimeUnit.MILLISECONDS.toDays(diffInMillis);
            case HOURS -> TimeUnit.MILLISECONDS.toHours(diffInMillis);
            case MINUTES -> TimeUnit.MILLISECONDS.toMinutes(diffInMillis);
            default -> throw new IllegalArgumentException("不支持的时间单位");
        };
        // æ ¡éªŒæ—¶é—´è·¨åº¦ä¸è¶…过最大限制
        if (diff > maxValue) {
            throw new ServiceException("最大时间跨度为 " + maxValue + " " + unit.toString().toLowerCase());
        }
    }
}