Java对时间切片,对时间分片,时间切割

发布时间 2023-05-07 23:21:16作者: 沙里

我们在数据查询或者数据导出的时候,经常因为时间跨度过大,降低了导出性能。

为了提高性能,我们往往需要对时间进行切分查询,鉴于此,我们需要对时间段,进行切分。

需要一个工具的时候,不应该是先造轮子,而是先寻找别人已经造好的轮子,我到了java时间切片工具 时间切割 时间切分,但是不是很满意。

因为为了提高查询效率,往往我们也会去缓存查询到结果,例如用时间区间做 key 去缓存。但是如果你的时间切割的不合理就会造成很多缓存无法命中。

为了提高时间切片查询缓存的命中率,我决定花时间去造个轮子。

如果它对你的工作和学习有所帮助,请你不要吝惜你的。


import cn.hutool.core.date.LocalDateTimeUtil;
import lombok.Data;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

public class TimeUtil {
    @Data
    public static class TimePage {
        /**
         * 分片查询开始时间
         */
        private LocalDateTime startDateTime;

        /**
         * 分片查询结束时间
         */
        private LocalDateTime endDateTime;

        /**
         * 下一次查询时间
         */
        private LocalDateTime nextStartDateTime;

        /**
         * 查询开始时间
         */
        private LocalDateTime beginDateTime;

        /**
         * 查询结束时间
         */
        private LocalDateTime finishDateTime;
    }

    public static TimePage genHighHitTimePage(TimePage timePage, long interval) {
        TimePage newTimePage = new TimePage();
        // 分片查询开始时间
        newTimePage.setBeginDateTime(timePage.getBeginDateTime());
        newTimePage.setFinishDateTime(timePage.getFinishDateTime());
        newTimePage.setStartDateTime(timePage.getStartDateTime());
        // 是否为第一次查询
        boolean isFirstQuery = timePage.getStartDateTime().isEqual(timePage.getBeginDateTime());
        // 分片查询结束时间
        if (isFirstQuery) {
            if ((interval / 86400) >= 1) {
                // 间隔超过 1 天 86400s
                newTimePage.setEndDateTime(LocalDateTimeUtil.offset(LocalDateTimeUtil.beginOfDay(newTimePage.getStartDateTime()), 1, ChronoUnit.DAYS));
            } else if ((interval / 3600) >= 1) {
                // 间隔超过1个小时
                long hours = newTimePage.getStartDateTime().getHour() + 1;
                newTimePage.setEndDateTime(LocalDateTimeUtil.offset(LocalDateTimeUtil.beginOfDay(newTimePage.getStartDateTime()), hours, ChronoUnit.HOURS));
            } else if ((interval / 60) >= 1) {
                // 间隔超过1分钟
                long minutes = newTimePage.getStartDateTime().getHour() * 60 + (newTimePage.getStartDateTime().getMinute() + 1);
                newTimePage.setEndDateTime(LocalDateTimeUtil.offset(LocalDateTimeUtil.beginOfDay(newTimePage.getStartDateTime()), minutes, ChronoUnit.MINUTES));
            } else {
                // 间隔小于1分钟
                newTimePage.setEndDateTime(LocalDateTimeUtil.offset(newTimePage.getStartDateTime(), interval, ChronoUnit.SECONDS));
            }
        } else {
            newTimePage.setEndDateTime(LocalDateTimeUtil.offset(newTimePage.getStartDateTime(), interval, ChronoUnit.SECONDS));
        }
        // 防止分片查询结束时间超过查询结束时间
        if (newTimePage.getEndDateTime().isAfter(newTimePage.getFinishDateTime())) {
            newTimePage.setEndDateTime(newTimePage.getFinishDateTime());
            newTimePage.setNextStartDateTime(null);
        } else {
            // 分片下次查询时间就是此次查询结束时间
            newTimePage.setNextStartDateTime(newTimePage.getEndDateTime());
        }

        return newTimePage;
    }
}

测试:

DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN);
String startDateTime = "2023-05-01 11:00:05";
String endDateTime = "2023-05-03 18:23:00";
// 间隔,单位秒
long interval = 86401L;
LocalDateTime startTime = LocalDateTime.parse(startDateTime, dateTimeFormatter);
LocalDateTime endTime = LocalDateTime.parse(endDateTime, dateTimeFormatter);
TimeUtil.TimePage timePage = new TimeUtil.TimePage();
timePage.setBeginDateTime(startTime);
timePage.setFinishDateTime(endTime);
timePage.setStartDateTime(startTime);
timePage.setEndDateTime(endTime);
TimeUtil.TimePage newTimePage = TimeUtil.genHighHitTimePage(timePage, interval);
System.out.println(newTimePage);
while (!newTimePage.getEndDateTime().isEqual(newTimePage.getFinishDateTime())) {
    newTimePage.setStartDateTime(newTimePage.getNextStartDateTime());
    newTimePage.setEndDateTime(newTimePage.getFinishDateTime());
    newTimePage = TimeUtil.genHighHitTimePage(newTimePage, interval);
    System.out.println(newTimePage);
}

结果:

TimeUtil.TimePage(startDateTime=2023-05-01T11:00:05, endDateTime=2023-05-02T00:00, nextStartDateTime=2023-05-02T00:00, beginDateTime=2023-05-01T11:00:05, finishDateTime=2023-05-03T18:23)
TimeUtil.TimePage(startDateTime=2023-05-02T00:00, endDateTime=2023-05-03T00:00:01, nextStartDateTime=2023-05-03T00:00:01, beginDateTime=2023-05-01T11:00:05, finishDateTime=2023-05-03T18:23)
TimeUtil.TimePage(startDateTime=2023-05-03T00:00:01, endDateTime=2023-05-03T18:23, nextStartDateTime=null, beginDateTime=2023-05-01T11:00:05, finishDateTime=2023-05-03T18:23)

参考