You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
143 lines
5.7 KiB
143 lines
5.7 KiB
package cn.teammodel.utils;
|
|
|
|
import cn.teammodel.common.CommonConstant;
|
|
import cn.teammodel.config.exception.ServiceException;
|
|
import cn.teammodel.model.entity.school.School;
|
|
import lombok.AllArgsConstructor;
|
|
import lombok.Data;
|
|
|
|
import java.time.*;
|
|
import java.time.temporal.ChronoUnit;
|
|
import java.time.temporal.TemporalAdjusters;
|
|
import java.util.Comparator;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
/**
|
|
* 学校中年级,学年,日期相关的工具类
|
|
* @author winter
|
|
* @create 2023-11-28 10:15
|
|
*/
|
|
public class SchoolDateUtil {
|
|
|
|
/**
|
|
* 通过当前时间与学校的学期安排获取当前的学年
|
|
* 学校学期:
|
|
* <pre>
|
|
* "semesters": [
|
|
* {
|
|
* "name": "下学期",
|
|
* "start": 0,
|
|
* "month": 3,
|
|
* "day": 1,
|
|
* "id": "2"
|
|
* },
|
|
* {
|
|
* "name": "上学期",
|
|
* "start": 1,
|
|
* "month": 9,
|
|
* "day": 1,
|
|
* "id": "1"
|
|
* }
|
|
* <pre/>
|
|
* <p>
|
|
* 示例: 传参 2023.11.28 返回 2023学年上学期
|
|
* 注意: 处理跨年问题 -> 2024.1.1, 应该也是 2023学年上学期,同时你需要注意,semesters 可能不止两个学期
|
|
* </p>
|
|
*/
|
|
public static semesterModel getSemesterByNow(List<School.Semester> semesters, LocalDate date) {
|
|
if (semesters == null || semesters.isEmpty() || date == null) {
|
|
throw new ServiceException("semesters and date must not be null or empty.");
|
|
}
|
|
|
|
// 将 semester 根据大小排序
|
|
semesters.sort(Comparator.comparing(s -> LocalDate.of(date.getYear(), s.getMonth(), s.getDay())));
|
|
|
|
// i = 0 的日期是开学最早, i = size - 1 是开学最晚
|
|
int size = semesters.size();
|
|
// 拿到最晚开学的日期,将年份 - 1后,与头节点组成可跨年区间
|
|
School.Semester lastSemester = semesters.get(size - 1);
|
|
School.Semester firstSemester = semesters.get(0);
|
|
// 动态替换
|
|
LocalDate lastSemesterStart = LocalDate.of(date.getYear() - 1, lastSemester.getMonth(), lastSemester.getDay());
|
|
String lastSemesterId = lastSemester.getId();
|
|
for (School.Semester semester : semesters) {
|
|
// 特判头尾的提起,分别将学期区间提前和延后一年(不用延后),例如 2023.3.1 与 2023.9.1 我们分别向添加一个节点,划分其为 3 个区间:
|
|
// 2022.9.1 - 2023.3.1, 2023.3.1 - 2023.9.1, 2023.9.1 - 2024.3.1
|
|
LocalDate curSemesterStart = LocalDate.of(date.getYear(), semester.getMonth(), semester.getDay());
|
|
if (date.isEqual(lastSemesterStart) || date.isAfter(lastSemesterStart) && date.isBefore(curSemesterStart)) {
|
|
String academicYearId = generateCurAcademicId(lastSemesterStart.getYear(), lastSemesterId);
|
|
return new semesterModel(academicYearId, lastSemesterId, lastSemesterStart.atStartOfDay(), semester.getId(), curSemesterStart.atStartOfDay());
|
|
}
|
|
lastSemesterStart = curSemesterStart;
|
|
lastSemesterId = semester.getId();
|
|
}
|
|
|
|
// 剩下的时间段, 学年应该就是最后一个学年. 学期末就应该是下一年(year + 1)的第一个节点
|
|
String academicYearId = generateCurAcademicId(date.getYear(), lastSemester.getId());
|
|
return new semesterModel(
|
|
academicYearId,
|
|
lastSemester.getId(),
|
|
LocalDate.of(date.getYear(), lastSemester.getMonth(), lastSemester.getDay()).atStartOfDay(),
|
|
firstSemester.getId(),
|
|
LocalDate.of(date.getYear() + 1, firstSemester.getMonth(), firstSemester.getDay()).atStartOfDay()
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 返回 ID -> 学年(组合 id: 学年-semesterId -> 2023-{semesterId})
|
|
*/
|
|
private static String generateCurAcademicId(int academicYear, String semesterId) {
|
|
return academicYear + CommonConstant.DASH + semesterId;
|
|
}
|
|
|
|
public static String calculateAcademicYearId(List<School.Semester> semesters, LocalDate date) {
|
|
return getSemesterByNow(semesters, date).getAcademicYearId();
|
|
}
|
|
/**
|
|
* 计算一学期相对的周数<br/>
|
|
* 如果 timeStamp 为 null, 则返回当前学期的总周数
|
|
*/
|
|
public static long calculateWeekNum(LocalDateTime startDateTime, LocalDateTime endDateTime, Long timeStamp) {
|
|
if (timeStamp == null) {
|
|
return ChronoUnit.WEEKS.between(startDateTime, endDateTime) + 1;
|
|
} else {
|
|
LocalDateTime curDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(timeStamp), ZoneOffset.of("+08:00"));
|
|
startDateTime = startDateTime.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY))
|
|
.withHour(0)
|
|
.withMinute(0)
|
|
.withSecond(0)
|
|
.withNano(0);
|
|
// 如果传参没在学期范围内, 返回 -1
|
|
if (curDateTime.isBefore(startDateTime) || curDateTime.isAfter(endDateTime)) {
|
|
return -1;
|
|
}
|
|
return ChronoUnit.WEEKS.between(startDateTime, curDateTime) + 1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 创建初始化的 Map
|
|
*/
|
|
public static Map<Long, Integer> createEmptyWeekMap(long totalWeek) {
|
|
Map<Long, Integer> initialMap = new HashMap<>();
|
|
for (long i = 1; i <= totalWeek; i++) {
|
|
initialMap.put(i, 0);
|
|
}
|
|
return initialMap;
|
|
}
|
|
|
|
|
|
@Data
|
|
@AllArgsConstructor
|
|
public static class semesterModel {
|
|
private String academicYearId;
|
|
private String startSemesterId;
|
|
private LocalDateTime startDatetime;
|
|
private String endSemesterId;
|
|
private LocalDateTime endDatetime;
|
|
}
|
|
|
|
}
|