The company recently wants to do statistics on data indicators, some time conversion analysis of week-to-week and month-to-month comparisons, date function chaos
package com.renrenche.business.sale.customer.manage.infrastructure.general.util; import com.google.common.collect.Lists; import com.renrenche.business.sale.customer.manage.domain.common.bean.TimeRangeParam; import lombok.experimental.UtilityClass; import org.springframework.util.CollectionUtils; 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.Collectors; import java.util.stream.Stream; /** * @author liulei44 * @date 2023/5/10 12:06 AM */ @UtilityClass public class WeekMonthUtil {<!-- --> public static final String DATE_STR_FORMAT = "yyyy-MM-dd"; public static final String START_TIME = "startTime"; public static final String END_TIME = "endTime"; public static final Integer START = 0; public static final Integer END = 1; /** * Get the time span of a certain week in a certain year * * @param year year * @param week week number * @return k-v */ private static Map<String, String> getWeekRangeMap(int year, int week) {<!-- --> Map<String, String> dateMap = new HashMap<>(8); Calendar calendar = Calendar. getInstance(); calendar.set(Calendar.YEAR, year); // Set Monday as the first day of the week calendar.setFirstDayOfWeek(Calendar.MONDAY); // can not be set calendar.setMinimalDaysInFirstWeek(4); // get the current year int weekYear = calendar. get(Calendar. YEAR); // Get the start date of the week of the specified year (day of the week) calendar.setWeekDate(weekYear, week, Calendar.MONDAY); Date time = calendar. getTime(); String startTime = new SimpleDateFormat(DATE_STR_FORMAT).format(time); dateMap.put(START_TIME, startTime); // Get the end date of the week of the specified year (day of the week) calendar.setWeekDate(weekYear, week, Calendar.SUNDAY); time = calendar. getTime(); String endTime = new SimpleDateFormat(DATE_STR_FORMAT).format(time); dateMap.put(END_TIME, endTime); return dateMap; } /** * Get how many weeks there are in a year * * @param year year * @return The total number of weeks in the current year */ public static int getYearWeekCount(int year) {<!-- --> int week = 52; try {<!-- --> Map<String, String> timeMap = getWeekRangeMap(year, 53); if (!CollectionUtils.isEmpty(timeMap)) {<!-- --> String startTime = timeMap. get(START_TIME); if (startTime.substring(0, 4).equals(year + "")) {<!-- --> // Determine whether the year matches, if it matches, there are 53 weeks. week = 53; } } } catch (Exception e) {<!-- --> e.printStackTrace(); } return week; } /** * Get the date span of all weeks in a year * * @param year year * @return list the date range of all weeks in the current year */ public static List<Map<String, String>> getYearWeekMap(int year) {<!-- --> int weeks = getYearWeekCount(year); List<Map<String, String>> yearWeekMap = new ArrayList<>(); for (int i = 1; i <= weeks; i ++ ) {<!-- --> Map<String, String> dateMap = getWeekRangeMap(year, i); yearWeekMap.add(dateMap); } return yearWeekMap; } /** * Get the week start and week end time of the date */ public static Date[] getWeekPeriodByDate(Date date) {<!-- --> Calendar calendar = Calendar. getInstance(); calendar. setTime(date); // start of the week if (calendar. get(Calendar. DAY_OF_WEEK) == Calendar. SUNDAY) {<!-- --> calendar. add(Calendar. DAY_OF_YEAR, -1); } calendar.add(Calendar.DAY_OF_WEEK, -(calendar.get(Calendar.DAY_OF_WEEK) - 2)); calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar. MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); long startTime = calendar. getTimeInMillis(); // end of the week calendar. add(Calendar. DAY_OF_WEEK, 6); calendar.set(Calendar.HOUR_OF_DAY, 23); calendar.set(Calendar.MINUTE, 59); calendar.set(Calendar.SECOND, 59); calendar.set(Calendar.MILLISECOND, 999); long endTime = calendar. getTimeInMillis(); return new Date[]{<!-- -->new Date(startTime), new Date(endTime)}; } /** * Get the absolute value of the month difference between two dates */ public static int getMonthSpace(Date date1, Date date2) {<!-- --> int result; Calendar c1 = Calendar. getInstance(); Calendar c2 = Calendar. getInstance(); c1.setTime(date1); c2.setTime(date2); int i = c2.get(Calendar.YEAR) - c1.get(Calendar.YEAR); int month = 0; if (i < 0) {<!-- --> month = -i * 12; } else if (i > 0) {<!-- --> month = i * 12; } result = (c2.get(Calendar.MONTH) - c1.get(Calendar.MONTH)) + month; return Math.abs(result); } /** * Get the date at the end of the month */ public static Date getMonthEndDate(Date date) {<!-- --> Calendar calendar = Calendar. getInstance(); calendar. setTime(date); calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH)); return calendar. getTime(); } /** * Get the date of the beginning of the month */ public static Date getMonthBeginDate(Date date) {<!-- --> Calendar calendar = Calendar. getInstance(); calendar. setTime(date); calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH)); return calendar. getTime(); } /** * Get the number of days in a month */ public static int getDaysOfMonth(Date date) {<!-- --> Instant instant = date.toInstant(); ZoneId zoneId = ZoneId. systemDefault(); LocalDate startDate = instant. atZone(zoneId).toLocalDate(); return startDate. lengthOfMonth(); } /** * According to the date --> the information of the week spanning the month */ public static WeekMonthInfo getWeekMonthInfo(Date date) {<!-- --> Date[] currentWeekTimeFrame = WeekMonthUtil.getWeekPeriodByDate(date); Date weekStart = currentWeekTimeFrame[START]; Date weekEnd = currentWeekTimeFrame[END]; int monthSpace = WeekMonthUtil. getMonthSpace(weekStart, weekEnd); //Initialization data WeekMonthInfo weekMonthInfo = WeekMonthInfo. builder() .preMonth(DateUtils.getMonth(DateUtils.addMonths(date,-1))) .preMonthAllDays(WeekMonthUtil.getDaysOfMonth(DateUtils.addMonths(date,-1))) .curMonth(DateUtils.getMonth(date)) .curMonthAllDays(WeekMonthUtil.getDaysOfMonth(date)) .curMonthPassDays(WeekMonthUtil.getMonthPassDays(date)) .curWeekAllDays(7) .build(); // processing across months if (monthSpace > 0) {<!-- --> Date monthEndDate = WeekMonthUtil. getMonthEndDate(weekStart); int preIntervalDays = Math.abs(DateUtils.getIntervalDays(weekStart, monthEndDate)); weekMonthInfo.setPreMonthCrossDays(preIntervalDays + 1); weekMonthInfo.setCurWeekAllDays(7-weekMonthInfo.getPreMonthCrossDays()); } int curIntervalDays = Math.abs(DateUtils.getIntervalDays(weekStart, date)); weekMonthInfo.setCurWeekPassDays(curIntervalDays + 1); return weekMonthInfo; } /** * According to the date --> get the number of days that have passed */ public static int getMonthPassDays(Date date) {<!-- --> Calendar calendar = Calendar. getInstance(); calendar. setTime(date); int passDays = calendar. get(Calendar. DAY_OF_MONTH); return passDays; } /** * Get the start and end time of the previous X weeks [including the current week] * * @param date current time * @param preNum the previous X weeks * @param cycle Whether the same period */ public static List<TimeRangeParam> getPreWeeksFromCurrent(Date date, int preNum, boolean cycle) {<!-- --> Calendar cal = Calendar. getInstance(); cal. setTime(date); // Set Monday as the start week of each week cal.setFirstDayOfWeek(Calendar.MONDAY); List<TimeRangeParam> result = Lists. newArrayList(); // add the current week SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date weekFirstDay = getWeekPeriodByDate(date)[START]; Date weekLastDay = getWeekPeriodByDate(cal. getTime())[END]; // The pass is year-on-year, just control the end time if (cycle) {<!-- --> weekLastDay = date; } result.add(new TimeRangeParam(sdf.format(weekFirstDay.getTime()), sdf.format(DateUtils.getDayEndTime(weekLastDay)))); // add the previous 4 weeks for (int i = 0; i < preNum; i ++ ) {<!-- --> weekFirstDay = DateUtils. addDays(weekFirstDay, -7); weekLastDay = DateUtils. addDays(weekLastDay, -7); result.add(new TimeRangeParam(sdf.format(weekFirstDay), sdf.format(DateUtils.getDayEndTime(weekLastDay)))); } Collections. reverse(result); return result; } /** * Get the start time of X months from the current time */ public static Long getMonthStartTime(Date date, int num) {<!-- --> long currentTime = date. getTime(); String timeZone = "GMT+8:00"; Calendar calendar = Calendar.getInstance();// Get the current date calendar.setTimeZone(TimeZone.getTimeZone(timeZone)); calendar.setTimeInMillis(currentTime); calendar. add(Calendar. YEAR, 0); calendar. add(Calendar. MONTH, num); calendar.set(Calendar.DAY_OF_MONTH, 1);// Set to 1st, the current date is the first day of this month calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar. MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); return calendar. getTimeInMillis(); } /** * Get the end time of the current X month */ public static Long getMonthEndTime(Date date, int num) {<!-- --> long currentTime = date. getTime(); String timeZone = "GMT+8:00"; Calendar calendar = Calendar.getInstance();// Get the current date calendar.setTimeZone(TimeZone.getTimeZone(timeZone)); calendar.setTimeInMillis(currentTime); calendar. add(Calendar. YEAR, 0); calendar. add(Calendar. MONTH, num); calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));// Get the last day of the current month calendar.set(Calendar.HOUR_OF_DAY, 23); calendar.set(Calendar.MINUTE, 59); calendar.set(Calendar.SECOND, 59); calendar.set(Calendar.MILLISECOND, 999); return calendar. getTimeInMillis(); } /** * Get the start and end time of the previous X month [including the current month] * * @param date current time * @param preNum the previous X months * @param cycle Whether the same period */ public static List<TimeRangeParam> getPreMonthsFromCurrent(Date date, int preNum, boolean cycle) {<!-- --> List<TimeRangeParam> result = Lists. newArrayList(); DateTimeFormatter ftf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); // the number of days in the current month LocalDateTime localDateTime = DateUtils.date2LocalDateTime(date); int curMonthDays = localDateTime.toLocalDate().lengthOfMonth(); int dayOfMonth = localDateTime. getDayOfMonth(); // If it is the whole month, then it does not need to be processed according to the same period, but the whole month is processed if (curMonthDays == dayOfMonth) {<!-- --> cycle = false; } // Accumulate the time of the previous preNum months for (int i = preNum; i > 0; i--) {<!-- --> Long startTime = getMonthStartTime(date, -i); Long endTime = getMonthEndTime(date, -i); String startTimeStr = ftf.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(startTime), ZoneId.systemDefault())); String endTimeStr; if (cycle) {<!-- --> LocalDateTime endLocalDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(endTime), ZoneId.systemDefault()); int monthDays = endLocalDateTime.toLocalDate().lengthOfMonth(); // If the total number of days in the month is smaller than the current number of days, round up the month if (monthDays <= dayOfMonth) {<!-- --> endTimeStr = ftf. format(endLocalDateTime); } else {<!-- --> Long dayEndTime = DateUtils.getDayEndTime(DateUtils.addMonths(date, -i)); endTimeStr = ftf.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(dayEndTime), ZoneId.systemDefault())); } } else {<!-- --> endTimeStr = ftf.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(endTime), ZoneId.systemDefault())); } result.add(new TimeRangeParam(startTimeStr, endTimeStr)); } // plus the range of the current month Long startTime = getMonthStartTime(date, 0); Long endTime = getMonthEndTime(date, 0); String startTimeStr = ftf.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(startTime), ZoneId.systemDefault())); String endTimeStr = ftf.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(endTime), ZoneId.systemDefault())); // If it is year-on-year, control the end time if (cycle) {<!-- --> endTimeStr = ftf.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(DateUtils.getDayEndTime(date)), ZoneId.systemDefault())); } result.add(new TimeRangeParam(startTimeStr, endTimeStr)); return result; } /** * Get month information */ public static int getMonthByDateStr(String dateStr) throws ParseException {<!-- --> SimpleDateFormat formatter = new SimpleDateFormat(DATE_STR_FORMAT); Date date = formatter. parse(dateStr); LocalDate localDate = DateUtils.date2LocalDate(date); return localDate. getMonthValue(); } /** * Given a start and end time, calculate the number of days the week spans */ public static WeekInfo getWeekCrossInfoByPeriod(Date start, Date end) {<!-- --> if (start.after(end)) {<!-- --> throw new RuntimeException("The parameter is abnormal, the week information cannot be calculated"); } LocalDate startDate = DateUtils.date2LocalDate(start); LocalDate endDate = DateUtils.date2LocalDate(end); WeekInfo weekInfo = WeekInfo. builder() .curMonth(endDate.getMonthValue()) .curMonthDays(endDate.lengthOfMonth()) .build(); // If the week spans the previous month and the current month, you need to calculate how many days they span the previous month and the current month if (startDate.getMonthValue() != endDate.getMonthValue()) {<!-- --> weekInfo.setPreMonth(startDate.getMonthValue()); weekInfo.setPreMonthDays(startDate.lengthOfMonth()); // Calculate how many days the week spans the previous month LocalDate preMonthLastDate = startDate.with(TemporalAdjusters.lastDayOfMonth()); weekInfo.setPreMonthCrossDays(preMonthLastDate.getDayOfMonth() - startDate.getDayOfMonth() + 1); // Calculate the number of days in the month of the week LocalDate curMonthFirstDate = endDate.with(TemporalAdjusters.firstDayOfMonth()); weekInfo.setCurMonthCrossDays(endDate.getDayOfMonth() - curMonthFirstDate.getDayOfMonth() + 1); } else {<!-- --> // If the week is in the same month, you only need to calculate the number of days in the week [actually 7 days] LocalDate preMonth = DateUtils.date2LocalDate(DateUtils.addMonths(end, -1)); weekInfo.setPreMonth(preMonth.getMonthValue()); weekInfo.setPreMonthDays(preMonth.lengthOfMonth()); int daysInCurrentMonth = endDate.getDayOfMonth() - startDate.getDayOfMonth() + 1; weekInfo.setCurMonthCrossDays(daysInCurrentMonth); } return weekInfo; } /** * Get all data between two dates */ public static List<String> getPeriodDateStr(String start, String end) {<!-- --> LocalDate timeStart = LocalDate. parse(start); LocalDate timeEnd = LocalDate. parse(end); return Stream.iterate(timeStart, localDate -> localDate.plusDays(1)) .limit(ChronoUnit.DAYS.between(timeStart, timeEnd) + 1) .map(localDate -> localDate.toString().replaceAll("-","")) .collect(Collectors.toList()); } }
Test Case
package com.renrenche.business.sale.customer.manage.infrastructure.utils; import com.alibaba.fastjson.JSON; import com.google.common.collect.Lists; import com.google.common.collect.Lists; import com.renrenche.business.sale.customer.manage.domain.common.bean.TimeRangeParam; import com.renrenche.business.sale.customer.manage.infrastructure.general.util.SpringUtil; import com.renrenche.business.sale.customer.manage.infrastructure.general.util.WeekInfo; import com.renrenche.business.sale.customer.manage.infrastructure.general.util.WeekMonthInfo; import com.renrenche.business.sale.customer.manage.infrastructure.general.util.WeekMonthInfo; import com.renrenche.business.sale.customer.manage.infrastructure.general.util.WeekMonthUtil; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; /** * @author liulei44 * @date 2023/5/10 12:58 AM */ @RunWith(PowerMockRunner. class) @PrepareForTest(SpringUtil. class) public class WeekInfoUtilTest {<!-- --> // Get the week information of the date @Test public void dateWeekInfo() throws ParseException {<!-- --> SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); List<String> param = Lists. newArrayList(); param.add("2023-05-10"); param.add("2023-02-02"); param.add("2022-12-30"); for (String dateStr : param) {<!-- --> Date date = formatter. parse(dateStr); WeekMonthInfo weekInfo = WeekMonthUtil. getWeekMonthInfo(date); System.out.println(dateStr + "=>" + JSON.toJSONString(weekInfo)); } } // Get the span information of the week information [week start time - week end time] @Test public void getWeeksCrossMonthByPeriod() throws ParseException {<!-- --> // [2023-02-27,2023-03-05] SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); Date start = formatter. parse("2023-02-27"); Date end = formatter. parse("2023-03-05"); WeekInfo weekInfo = WeekMonthUtil. getWeekCrossInfoByPeriod(start, end); System.out.println(JSON.toJSONString(weekInfo)); // [2023-11-27,2023-12-03] start = formatter. parse("2023-11-27"); end = formatter. parse("2023-12-03"); weekInfo = WeekMonthUtil.getWeekCrossInfoByPeriod(start, end); System.out.println(JSON.toJSONString(weekInfo)); // [2023-04-10, 2023-04-16] start = formatter. parse("2023-04-10"); end = formatter. parse("2023-04-16"); weekInfo = WeekMonthUtil.getWeekCrossInfoByPeriod(start, end); System.out.println(JSON.toJSONString(weekInfo)); Assert.assertEquals(7, weekInfo.getCurMonthCrossDays()); // [2023-04-10, 2023-04-16] start = formatter. parse("2023-05-10"); end = formatter. parse("2023-05-12"); weekInfo = WeekMonthUtil.getWeekCrossInfoByPeriod(start, end); System.out.println(JSON.toJSONString(weekInfo)); Assert.assertEquals(3, weekInfo.getCurMonthCrossDays()); } @Test public void getMonthTest() throws ParseException {<!-- --> int month = WeekMonthUtil.getMonthByDateStr("2023-02-27"); Assert.assertEquals(2, month); } // get the current month + previous 4 months @Test public void getPreMonthsFromCurrentTest() throws Exception {<!-- --> SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); List<Date> paramList = Lists. newArrayList(); paramList.add(formatter.parse("2023-05-10 00:00:00")); paramList.add(formatter.parse("2023-03-29 00:00:00")); paramList.add(formatter.parse("2023-02-20 00:00:00")); paramList.add(formatter.parse("2022-12-30 00:00:00")); for (Date date : paramList) {<!-- --> List<TimeRangeParam> preMonthsFromCurrent = WeekMonthUtil.getPreMonthsFromCurrent(date, 4, true); Assert.assertEquals(5, preMonthsFromCurrent.size()); System.out.println("preMonthsFromCurrent-" + JSON.toJSONString(preMonthsFromCurrent)); preMonthsFromCurrent = WeekMonthUtil.getPreMonthsFromCurrent(date, 4, false); Assert.assertEquals(5, preMonthsFromCurrent.size()); System.out.println("General Months-" + JSON.toJSONString(preMonthsFromCurrent)); } } // Get the current week + previous four weeks @Test public void getPreWeeks() throws ParseException {<!-- --> SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); List<Date> param = Lists. newArrayList(); param.add(formatter.parse("2023-02-27 00:00:00")); param.add(formatter.parse("2023-01-24 00:00:00")); param.add(formatter.parse("2023-04-22 00:00:00")); param.add(formatter.parse("2023-05-10 00:00:00")); for (Date date : param) {<!-- --> List<TimeRangeParam> weeks = WeekMonthUtil.getPreWeeksFromCurrent(date, 4, false); Assert.assertEquals(5, weeks.size()); System.out.println("Normal week:" + JSON.toJSONString(weeks)); weeks = WeekMonthUtil.getPreWeeksFromCurrent(date, 4, true); Assert.assertEquals(5, weeks.size()); System.out.println("weekly year-on-year:" + JSON.toJSONString(weeks)); } } }