dengzedong
4 天以前 730d1944e3a13c517c77df2b0712df05645a38dd
提交 | 用户 | 时间
e7c126 1 package com.iailab.framework.common.util.date;
H 2
3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.date.DatePattern;
5 import cn.hutool.core.date.LocalDateTimeUtil;
6 import cn.hutool.core.lang.Assert;
7 import cn.hutool.core.util.StrUtil;
8 import com.iailab.framework.common.enums.DateIntervalEnum;
9
10 import java.time.*;
11 import java.time.format.DateTimeParseException;
12 import java.time.temporal.ChronoUnit;
13 import java.time.temporal.TemporalAdjusters;
14 import java.util.ArrayList;
15 import java.util.List;
16
17 /**
18  * 时间工具类,用于 {@link java.time.LocalDateTime}
19  *
20  * @author iailab
21  */
22 public class LocalDateTimeUtils {
23
24     /**
25      * 空的 LocalDateTime 对象,主要用于 DB 唯一索引的默认值
26      */
27     public static LocalDateTime EMPTY = buildTime(1970, 1, 1);
28
29     /**
30      * 解析时间
31      *
32      * 相比 {@link LocalDateTimeUtil#parse(CharSequence)} 方法来说,会尽量去解析,直到成功
33      *
34      * @param time 时间
35      * @return 时间字符串
36      */
37     public static LocalDateTime parse(String time) {
38         try {
39             return LocalDateTimeUtil.parse(time, DatePattern.NORM_DATE_PATTERN);
40         } catch (DateTimeParseException e) {
41             return LocalDateTimeUtil.parse(time);
42         }
43     }
44
45     public static LocalDateTime addTime(Duration duration) {
46         return LocalDateTime.now().plus(duration);
47     }
48
49     public static LocalDateTime minusTime(Duration duration) {
50         return LocalDateTime.now().minus(duration);
51     }
52
53     public static boolean beforeNow(LocalDateTime date) {
54         return date.isBefore(LocalDateTime.now());
55     }
56
57     public static boolean afterNow(LocalDateTime date) {
58         return date.isAfter(LocalDateTime.now());
59     }
60
61     /**
62      * 创建指定时间
63      *
64      * @param year  年
65      * @param mouth 月
66      * @param day   日
67      * @return 指定时间
68      */
69     public static LocalDateTime buildTime(int year, int mouth, int day) {
70         return LocalDateTime.of(year, mouth, day, 0, 0, 0);
71     }
72
73     public static LocalDateTime[] buildBetweenTime(int year1, int mouth1, int day1,
74                                                    int year2, int mouth2, int day2) {
75         return new LocalDateTime[]{buildTime(year1, mouth1, day1), buildTime(year2, mouth2, day2)};
76     }
77
78     /**
79      * 判指定断时间,是否在该时间范围内
80      *
81      * @param startTime 开始时间
82      * @param endTime 结束时间
83      * @param time 指定时间
84      * @return 是否
85      */
86     public static boolean isBetween(LocalDateTime startTime, LocalDateTime endTime, String time) {
87         if (startTime == null || endTime == null || time == null) {
88             return false;
89         }
90         return LocalDateTimeUtil.isIn(parse(time), startTime, endTime);
91     }
92
93     /**
94      * 判断当前时间是否在该时间范围内
95      *
96      * @param startTime 开始时间
97      * @param endTime   结束时间
98      * @return 是否
99      */
100     public static boolean isBetween(LocalDateTime startTime, LocalDateTime endTime) {
101         if (startTime == null || endTime == null) {
102             return false;
103         }
104         return LocalDateTimeUtil.isIn(LocalDateTime.now(), startTime, endTime);
105     }
106
107     /**
108      * 判断当前时间是否在该时间范围内
109      *
110      * @param startTime 开始时间
111      * @param endTime   结束时间
112      * @return 是否
113      */
114     public static boolean isBetween(String startTime, String endTime) {
115         if (startTime == null || endTime == null) {
116             return false;
117         }
118         LocalDate nowDate = LocalDate.now();
119         return LocalDateTimeUtil.isIn(LocalDateTime.now(),
120                 LocalDateTime.of(nowDate, LocalTime.parse(startTime)),
121                 LocalDateTime.of(nowDate, LocalTime.parse(endTime)));
122     }
123
124     /**
125      * 判断时间段是否重叠
126      *
127      * @param startTime1 开始 time1
128      * @param endTime1   结束 time1
129      * @param startTime2 开始 time2
130      * @param endTime2   结束 time2
131      * @return 重叠:true 不重叠:false
132      */
133     public static boolean isOverlap(LocalTime startTime1, LocalTime endTime1, LocalTime startTime2, LocalTime endTime2) {
134         LocalDate nowDate = LocalDate.now();
135         return LocalDateTimeUtil.isOverlap(LocalDateTime.of(nowDate, startTime1), LocalDateTime.of(nowDate, endTime1),
136                 LocalDateTime.of(nowDate, startTime2), LocalDateTime.of(nowDate, endTime2));
137     }
138
139     /**
140      * 获取指定日期所在的月份的开始时间
141      * 例如:2023-09-30 00:00:00,000
142      *
143      * @param date 日期
144      * @return 月份的开始时间
145      */
146     public static LocalDateTime beginOfMonth(LocalDateTime date) {
147         return date.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
148     }
149
150     /**
151      * 获取指定日期所在的月份的最后时间
152      * 例如:2023-09-30 23:59:59,999
153      *
154      * @param date 日期
155      * @return 月份的结束时间
156      */
157     public static LocalDateTime endOfMonth(LocalDateTime date) {
158         return date.with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX);
159     }
160
161     /**
162      * 获得指定日期所在季度
163      *
164      * @param date 日期
165      * @return 所在季度
166      */
167     public static int getQuarterOfYear(LocalDateTime date) {
168         return (date.getMonthValue() - 1) / 3 + 1;
169     }
170
171     /**
172      * 获取指定日期到现在过了几天,如果指定日期在当前日期之后,获取结果为负
173      *
174      * @param dateTime 日期
175      * @return 相差天数
176      */
177     public static Long between(LocalDateTime dateTime) {
178         return LocalDateTimeUtil.between(dateTime, LocalDateTime.now(), ChronoUnit.DAYS);
179     }
180
181     /**
182      * 获取今天的开始时间
183      *
184      * @return 今天
185      */
186     public static LocalDateTime getToday() {
187         return LocalDateTimeUtil.beginOfDay(LocalDateTime.now());
188     }
189
190     /**
191      * 获取昨天的开始时间
192      *
193      * @return 昨天
194      */
195     public static LocalDateTime getYesterday() {
196         return LocalDateTimeUtil.beginOfDay(LocalDateTime.now().minusDays(1));
197     }
198
199     /**
200      * 获取本月的开始时间
201      *
202      * @return 本月
203      */
204     public static LocalDateTime getMonth() {
205         return beginOfMonth(LocalDateTime.now());
206     }
207
208     /**
209      * 获取本年的开始时间
210      *
211      * @return 本年
212      */
213     public static LocalDateTime getYear() {
214         return LocalDateTime.now().with(TemporalAdjusters.firstDayOfYear()).with(LocalTime.MIN);
215     }
216
217     public static List<LocalDateTime[]> getDateRangeList(LocalDateTime startTime,
218                                                          LocalDateTime endTime,
219                                                          Integer interval) {
220         // 1.1 找到枚举
221         DateIntervalEnum intervalEnum = DateIntervalEnum.valueOf(interval);
222         Assert.notNull(intervalEnum, "interval({}} 找不到对应的枚举", interval);
223         // 1.2 将时间对齐
224         startTime = LocalDateTimeUtil.beginOfDay(startTime);
225         endTime = LocalDateTimeUtil.endOfDay(endTime);
226
227         // 2. 循环,生成时间范围
228         List<LocalDateTime[]> timeRanges = new ArrayList<>();
229         switch (intervalEnum) {
230             case DAY:
231                 while (startTime.isBefore(endTime)) {
232                     timeRanges.add(new LocalDateTime[]{startTime, startTime.plusDays(1).minusNanos(1)});
233                     startTime = startTime.plusDays(1);
234                 }
235                 break;
236             case WEEK:
237                 while (startTime.isBefore(endTime)) {
238                     LocalDateTime endOfWeek = startTime.with(DayOfWeek.SUNDAY).plusDays(1).minusNanos(1);
239                     timeRanges.add(new LocalDateTime[]{startTime, endOfWeek});
240                     startTime = endOfWeek.plusNanos(1);
241                 }
242                 break;
243             case MONTH:
244                 while (startTime.isBefore(endTime)) {
245                     LocalDateTime endOfMonth = startTime.with(TemporalAdjusters.lastDayOfMonth()).plusDays(1).minusNanos(1);
246                     timeRanges.add(new LocalDateTime[]{startTime, endOfMonth});
247                     startTime = endOfMonth.plusNanos(1);
248                 }
249                 break;
250             case QUARTER:
251                 while (startTime.isBefore(endTime)) {
252                     int quarterOfYear = getQuarterOfYear(startTime);
253                     LocalDateTime quarterEnd = quarterOfYear == 4
254                             ? startTime.with(TemporalAdjusters.lastDayOfYear()).plusDays(1).minusNanos(1)
255                             : startTime.withMonth(quarterOfYear * 3 + 1).withDayOfMonth(1).minusNanos(1);
256                     timeRanges.add(new LocalDateTime[]{startTime, quarterEnd});
257                     startTime = quarterEnd.plusNanos(1);
258                 }
259                 break;
260             case YEAR:
261                 while (startTime.isBefore(endTime)) {
262                     LocalDateTime endOfYear = startTime.with(TemporalAdjusters.lastDayOfYear()).plusDays(1).minusNanos(1);
263                     timeRanges.add(new LocalDateTime[]{startTime, endOfYear});
264                     startTime = endOfYear.plusNanos(1);
265                 }
266                 break;
267             default:
268                 throw new IllegalArgumentException("Invalid interval: " + interval);
269         }
270         // 3. 兜底,最后一个时间,需要保持在 endTime 之前
271         LocalDateTime[] lastTimeRange = CollUtil.getLast(timeRanges);
272         if (lastTimeRange != null) {
273             lastTimeRange[1] = endTime;
274         }
275         return timeRanges;
276     }
277
278     /**
279      * 格式化时间范围
280      *
281      * @param startTime 开始时间
282      * @param endTime   结束时间
283      * @param interval  时间间隔
284      * @return 时间范围
285      */
286     public static String formatDateRange(LocalDateTime startTime, LocalDateTime endTime, Integer interval) {
287         // 1. 找到枚举
288         DateIntervalEnum intervalEnum = DateIntervalEnum.valueOf(interval);
289         Assert.notNull(intervalEnum, "interval({}} 找不到对应的枚举", interval);
290
291         // 2. 循环,生成时间范围
292         switch (intervalEnum) {
293             case DAY:
294                 return LocalDateTimeUtil.format(startTime, DatePattern.NORM_DATE_PATTERN);
295             case WEEK:
296                 return LocalDateTimeUtil.format(startTime, DatePattern.NORM_DATE_PATTERN)
297                         + StrUtil.format("(第 {} 周)", LocalDateTimeUtil.weekOfYear(startTime));
298             case MONTH:
299                 return LocalDateTimeUtil.format(startTime, DatePattern.NORM_MONTH_PATTERN);
300             case QUARTER:
301                 return StrUtil.format("{}-Q{}", startTime.getYear(), getQuarterOfYear(startTime));
302             case YEAR:
303                 return LocalDateTimeUtil.format(startTime, DatePattern.NORM_YEAR_PATTERN);
304             default:
305                 throw new IllegalArgumentException("Invalid interval: " + interval);
306         }
307     }
308
309 }