小工具:将传入的日期区间按日、周、月、季、年分隔成多个时间区间

/ 默认分类 / 没有评论 / 85浏览

最近在做公司项目的时候,有一个需求是需要传入一个开始时间和一个结束时间。但是要按照统计的方式分别以日、周、月、季、年的方式来分组进行统计。

这个问题其实有两个解决方案,一个是利用sql处理日期的字段格式化进行分组;另一种就是写一个通用一点的SQL,然后在service里处理这些日期,遍历调用这个接口。

由于我们的需求对时间的要求比较复杂,并不可以按照自然月的方式进行统计,而是上个月26到本月25日为一个周期。比如统计2019年1月,实际上的开始和结束时间为:2018-12-26~2019-01-25。也正是因为这点,使用sql分组的方式就更加难以实现。

所以我选用了第一个解决方案,就是在业务里处理这些时间。遂萌生了写这个工具类的想法。

因为我们的业务需求比较特殊,所以下边贴上的代码还是按照自然月来处理的。


import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 传开始和结束日期 按日、周、月、季、年分割成一些时间区间
 * <p>
 */
public class DateSeparateUtil {

    /**
     * 按日分隔
     *
     * @param startTime
     * @param endTime
     * @param format
     * @param timeForQuery 分隔好的时间区间 一个startTime和endTime为一组
     * @param timeForShow  显示在横轴的时间区间
     */
    public static void separateByDay(Date startTime, Date endTime, SimpleDateFormat format, List<Map<String, String>> timeForQuery, List<String> timeForShow) {
        if (timeForQuery == null) {
            timeForQuery = new ArrayList<>();
        }
        if (timeForShow == null) {
            timeForShow = new ArrayList<>();
        }

        Calendar start = Calendar.getInstance();
        start.setTime(startTime);
        Calendar end = Calendar.getInstance();
        end.setTime(endTime);

        while (start.getTimeInMillis() < end.getTimeInMillis()) {
            HashMap<String, String> map = new HashMap<>();
            String startStr = format.format(new Date(start.getTimeInMillis()));
            map.put("startTime", startStr + " 00:00:00"); // 按天算的话 开始和结束就是同一天
            map.put("endTime", startStr + " 23:59:59");
            timeForQuery.add(map);
            timeForShow.add(startStr.substring(5, 10));
            start.add(Calendar.DAY_OF_YEAR, 1);
        }
    }

    /**
     * 按星期分隔
     *
     * @param startTime
     * @param endTime
     * @param format
     * @param timeForQuery
     * @param timeForShow
     */
    public static void separateByWeek(Date startTime, Date endTime, SimpleDateFormat format, List<Map<String, String>> timeForQuery, List<String> timeForShow) {
        if (timeForQuery == null) {
            timeForQuery = new ArrayList<>();
        }
        if (timeForShow == null) {
            timeForShow = new ArrayList<>();
        }
        Calendar start = Calendar.getInstance();
        start.setFirstDayOfWeek(Calendar.MONDAY);
        start.setTime(startTime);
        Calendar end = Calendar.getInstance();
        end.setTime(endTime);

        while (start.getTimeInMillis() < end.getTimeInMillis()) {
            HashMap<String, String> map = new HashMap<>();
            String startStr = format.format(new Date(start.getTimeInMillis()));
            map.put("startTime", startStr + " 00:00:00");
            start.add(Calendar.DAY_OF_WEEK, /*start.getActualMaximum(Calendar.DAY_OF_WEEK)*/8 - start.get(Calendar.DAY_OF_WEEK));
            if (start.getTimeInMillis() > end.getTimeInMillis()) {
                // 结束日期不能超过传来的最后日期
                start.setTimeInMillis(end.getTimeInMillis());
            }
            String weekEnd = format.format(new Date(start.getTimeInMillis()));
            map.put("endTime", weekEnd + " 23:59:59");
            timeForQuery.add(map);
            timeForShow.add(startStr.substring(5, 10) + "/" + weekEnd.substring(5, 10));
            // 加一天到下一周
            start.add(Calendar.DAY_OF_WEEK, 1);
        }
    }

    /**
     * 按月分割
     *
     * @param startTime
     * @param endTime
     * @param format
     * @param timeForQuery
     * @param timeForShow
     */
    public static void separateByMonth(Date startTime, Date endTime, SimpleDateFormat format, List<Map<String, String>> timeForQuery, List<String> timeForShow) {
        if (timeForQuery == null) {
            timeForQuery = new ArrayList<>();
        }
        if (timeForShow == null) {
            timeForShow = new ArrayList<>();
        }
        Calendar start = Calendar.getInstance();
        start.setTime(startTime);
        Calendar end = Calendar.getInstance();
        end.setTime(endTime);

        while (start.getTimeInMillis() < end.getTimeInMillis()) {
            HashMap<String, String> map = new HashMap<>();
            String startStr = format.format(new Date(start.getTimeInMillis()));
            map.put("startTime", startStr + " 00:00:00");
         
            // region 按照自然月方式处理
             start.set(Calendar.DAY_OF_MONTH, start.getActualMaximum(Calendar.DAY_OF_MONTH));
            // endregion
            if (start.getTimeInMillis() > end.getTimeInMillis()) {
                start.setTimeInMillis(end.getTimeInMillis());// 不能超过end时期
            }
            Date monthEnd = new Date(start.getTimeInMillis());
            map.put("endTime", format.format(monthEnd) + " 23:59:59");
            timeForQuery.add(map);
            timeForShow.add(format.format(monthEnd).substring(2, 7));
            start.add(Calendar.DAY_OF_MONTH, 1); // 跳到下一天
        }
    }

    /**
     * 按季度拆分
     *
     * @param startTime
     * @param endTime
     * @param format
     * @param timeForQuery
     * @param timeForShow
     */
    public static void separateByQuarter(Date startTime, Date endTime, SimpleDateFormat format, List<Map<String, String>> timeForQuery, List<String> timeForShow) {
        if (timeForQuery == null) {
            timeForQuery = new ArrayList<>();
        }
        if (timeForShow == null) {
            timeForShow = new ArrayList<>();
        }
        Calendar start = Calendar.getInstance();
        start.setTime(startTime);
        Calendar end = Calendar.getInstance();
        end.setTime(endTime);

        List<Integer> quarter1 = Arrays.asList(0, 1, 2);
        List<Integer> quarter2 = Arrays.asList(3, 4, 5);
        List<Integer> quarter3 = Arrays.asList(6, 7, 8);
        List<Integer> quarter4 = Arrays.asList(9, 10, 11);

        while (start.getTimeInMillis() < end.getTimeInMillis()) {

            int curMonth = start.get(Calendar.MONTH); // 0-11
            
            // 处理第一季度的月份
            if (quarter1.contains(curMonth)) {
                handleQuarterOnce(quarter1, 1, timeForQuery, timeForShow, format, start, end);
            }
            // 处理第二季度的月份
            if (quarter2.contains(curMonth)) {
                handleQuarterOnce(quarter2, 2, timeForQuery, timeForShow, format, start, end);
            }
            // 处理第三季度的月份
            if (quarter3.contains(curMonth)) {
                handleQuarterOnce(quarter3, 3, timeForQuery, timeForShow, format, start, end);
            }
            // 处理第四季度的月份
            if (quarter4.contains(curMonth)) {
                handleQuarterOnce(quarter4, 4, timeForQuery, timeForShow, format, start, end);
            }
        }

    }

    /**
     * 按年分隔
     *
     * @param startTime
     * @param endTime
     * @param format
     * @param timeForQuery
     * @param timeForShow
     */
    public static void separateByYear(Date startTime, Date endTime, SimpleDateFormat format, List<Map<String, String>> timeForQuery, List<String> timeForShow) {
        if (timeForQuery == null) {
            timeForQuery = new ArrayList<>();
        }
        if (timeForShow == null) {
            timeForShow = new ArrayList<>();
        }
        Calendar start = Calendar.getInstance();
        start.setTime(startTime);
        Calendar end = Calendar.getInstance();
        end.setTime(endTime);

        while (start.getTimeInMillis() < end.getTimeInMillis()) {
            HashMap<String, String> map = new HashMap<>();
            String startStr = format.format(new Date(start.getTimeInMillis()));
            map.put("startTime", startStr + " 00:00:00");
            // region按自然月处理
            start.set(Calendar.DAY_OF_YEAR, start.getActualMaximum(Calendar.DAY_OF_YEAR));
            // endregion

            if (start.getTimeInMillis() > end.getTimeInMillis()) {
                start.setTimeInMillis(end.getTimeInMillis());
            }
            String yearEnd = format.format(new Date(start.getTimeInMillis()));
            map.put("endTime", yearEnd + " 23:59:59");
            timeForQuery.add(map);
            timeForShow.add(yearEnd.substring(0, 4));
            start.add(Calendar.DAY_OF_YEAR, 1);// 跳下一天
        }
    }

    /**************************************************私有方法*********************************************************/
    /**
     * 近供分割季度的方法使用
     *
     * @param monthInQuarter List<Integer> quarter1 = Arrays.asList(0, 1, 2);
     * @param quarter        1\2\3\4
     * @param timeForQuery
     * @param timeForShow
     * @param format
     * @param start
     * @param end
     */
    private static void handleQuarterOnce(List<Integer> monthInQuarter, int quarter, List<Map<String, String>> timeForQuery,
                                          List<String> timeForShow, SimpleDateFormat format, Calendar start, Calendar end) {
        HashMap<String, String> map = new HashMap<>();
        String startStr = format.format(start.getTimeInMillis());
        map.put("startTime", startStr + " 00:00:00");
        // 设置为季度最后一天
        // region 自然月的方式处理
        start.set(Calendar.MONTH, monthInQuarter.get(2));
        start.set(Calendar.DAY_OF_MONTH, start.getActualMaximum(Calendar.DAY_OF_MONTH));
        // endregion

        // 防止超出时间范围
        if (start.getTimeInMillis() > end.getTimeInMillis()) {
            start.setTimeInMillis(end.getTimeInMillis());
        }
        String quarterEnd = format.format(new Date(start.getTimeInMillis()));
        map.put("endTime", quarterEnd + " 23:59:59");
        timeForQuery.add(map);
        timeForShow.add(quarterEnd.substring(0, 4) + "年" + quarter + "季度");
        start.add(Calendar.DAY_OF_MONTH, 1);// +1天
    }


    /*****************************************************测试*********************************************************/

    public static void main(String[] args) throws Exception {
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.DAY_OF_YEAR, 300);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
//        Date now = new Date();
//        Date end = new Date(instance.getTimeInMillis());
        Date now = format.parse("2017-09-26");
        Date end = format.parse("2019-04-20");
//        List<Map<String, String>> maps = separateByDay(new Date(), new Date(instance.getTimeInMillis()), format);
//        System.out.println(maps);

        ArrayList<Map<String, String>> timeForQuery = new ArrayList<>();
        ArrayList<String> timeForShow = new ArrayList<>();
//        separateByWeek(now, end, format, timeForQuery, timeForShow);
//        separateByMonth(now, end, format, timeForQuery, timeForShow);
//        assert (!ObjectUtils.hasLength(timeForQuery)):"OJBK";
//        separateByQuarter(now, end, format, timeForQuery, timeForShow);
        separateByYear(now, end, format, timeForQuery, timeForShow);
        System.out.println(timeForQuery);
        System.out.println(timeForShow);
    }
}