截取日期时间段,保证在一个时间线上

以前做HR时候由于是copy的sap hr的表结构,sap有定界的概念,定界根据时间约束来表示数据开始结束日期在表中什么样的,无交叉,无重叠,连续等。以前根据业务场景写,每个表都写了一遍,没有用泛型和反射去实现公用写法。现在从另一个角度来写,带有些许算法的味儿。

1.普通写法,声明一个TimeEntity,业务代码去复制给TimeEntity就好。然后都围绕这个TimeEntity实现。最后再处理相关业务。工具类都是普通的工具类,所以不在这里贴出来了。

根据各种场景截取日期时间段,得到自己想要的。看注释里就明白了。


import cn.hutool.json.JSONUtil;
import com.xhj.framework.web.common.DateUtils;
import com.xhj.framework.web.common.StringUtils;
import lombok.Data;

import java.io.Serializable;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

public class TestDate1 {
    public static void main(String[] args) throws ParseException {

        List<TimeEntity> list =new ArrayList<TimeEntity>();
//        //场景1  测试通过
//        |------|  |--------| 表数据(需要修改开始结束日期)
//            |----------|    前端返回带有开始结束日期点位置数据(需要保证整条完整)
        TimeEntity oldE = new TimeEntity();
        oldE.setId("1");
        oldE.setStartDate("2023-12-31");
        oldE.setEndDate("2024-02-10");

        list.add(oldE);

        TimeEntity oldE2 = new TimeEntity();
        oldE2.setId("2");
        oldE2.setStartDate("2024-02-11");
        oldE2.setEndDate("2028-12-01");
        list.add(oldE2);

        TimeEntity newE = new TimeEntity();
        newE.setId("");
        newE.setStartDate("2024-01-01");
        newE.setEndDate("2024-04-20");

        //场景2  测试通过
//        // |--------------|
//        //         |--------------|
//        TimeEntity oldE = new TimeEntity();
//        oldE.setId("1");
//        oldE.setStartDate("2023-12-31");
//        oldE.setEndDate("2024-02-10");
//        list.add(oldE);
        //场景3  测试通过
//        //    |----------------|
//        //|---------|
//        TimeEntity oldE2 = new TimeEntity();
//        oldE2.setId("2");
//        oldE2.setStartDate("2024-02-11");
//        oldE2.setEndDate("2028-12-01");
//        list.add(oldE2);
        //场景4 测试通过
//        //  |--------------------|
//        //      |---------|
//        TimeEntity oldE = new TimeEntity();
//        oldE.setId("1");
//        oldE.setStartDate("2023-12-31");
//        oldE.setEndDate("2024-04-10");
//        list.add(oldE);

        //场景5
        //     |--------------|
        //  |--------------------|
//        TimeEntity oldE = new TimeEntity();
//        oldE.setId("1");
//        oldE.setStartDate("2023-12-31");
//        oldE.setEndDate("2024-04-10");
//        list.add(oldE);
//
//        TimeEntity newE = new TimeEntity();
//        newE.setId("");
//        newE.setStartDate("2023-11-31");
//        newE.setEndDate("2024-04-20");

        //场景6   测试通过,返回无交叉不用处理数据
        // |----------|        |----------|
        //               |---|
//        TimeEntity oldE = new TimeEntity();
//        oldE.setId("1");
//        oldE.setStartDate("2023-10-31");
//        oldE.setEndDate("2023-11-10");
//        list.add(oldE);
//
//        TimeEntity oldE1 = new TimeEntity();
//        oldE1.setId("2");
//        oldE1.setStartDate("2024-04-20");
//        oldE1.setEndDate("2024-11-10");
//        list.add(oldE1);
//
//        TimeEntity newE = new TimeEntity();
//        newE.setId("");
//        newE.setStartDate("2023-11-31");
//        newE.setEndDate("2024-03-20");

        //场景7 通过
        //   |-------| |--------|
        // |-------------------------|
//        TimeEntity oldE = new TimeEntity();
//        oldE.setId("1");
//        oldE.setStartDate("2023-10-31");
//        oldE.setEndDate("2023-11-10");
//        list.add(oldE);
//
//        TimeEntity oldE1 = new TimeEntity();
//        oldE1.setId("2");
//        oldE1.setStartDate("2024-04-20");
//        oldE1.setEndDate("2024-11-10");
//        list.add(oldE1);
//
//        TimeEntity newE = new TimeEntity();
//        newE.setId("");
//        newE.setStartDate("2023-09-30");
//        newE.setEndDate("2024-11-15");

        //场景8 通过
        //   |-------| |--------|
        //      |-------------------------|
//        TimeEntity oldE = new TimeEntity();
//        oldE.setId("1");
//        oldE.setStartDate("2023-10-31");
//        oldE.setEndDate("2023-11-10");
//        list.add(oldE);
//
//        TimeEntity oldE1 = new TimeEntity();
//        oldE1.setId("2");
//        oldE1.setStartDate("2023-12-20");
//        oldE1.setEndDate("2024-01-10");
//        list.add(oldE1);
//
//        TimeEntity newE = new TimeEntity();
//        newE.setId("");
//        newE.setStartDate("2023-11-05");
//        newE.setEndDate("2024-11-15");

        //场景9 通过
        //   |-------| |--------|
        //      |-------------------------|
//        TimeEntity oldE = new TimeEntity();
//        oldE.setId("1");
//        oldE.setStartDate("2023-10-31");
//        oldE.setEndDate("2023-11-10");
//        list.add(oldE);
//
//        TimeEntity oldE1 = new TimeEntity();
//        oldE1.setId("2");
//        oldE1.setStartDate("2023-12-20");
//        oldE1.setEndDate("2024-01-10");
//        list.add(oldE1);
//
//        TimeEntity newE = new TimeEntity();
//        newE.setId("");
//        newE.setStartDate("2023-09-05");
//        newE.setEndDate("2024-01-05");
        //场景10通过
        // |-------|  |---------|
        // |--------------------|
//        TimeEntity oldE = new TimeEntity();
//        oldE.setId("1");
//        oldE.setStartDate("2023-10-31");
//        oldE.setEndDate("2023-11-10");
//        list.add(oldE);
//
//        TimeEntity oldE1 = new TimeEntity();
//        oldE1.setId("2");
//        oldE1.setStartDate("2023-12-20");
//        oldE1.setEndDate("2024-01-10");
//        list.add(oldE1);
//
//        TimeEntity newE = new TimeEntity();
//        newE.setId("");
//        newE.setStartDate("2023-10-31");
//        newE.setEndDate("2024-01-10");
        //场景11通过
        // |-------|  |---------|
        // |--------------------|
//        TimeEntity oldE = new TimeEntity();
//        oldE.setId("1");
//        oldE.setStartDate("2023-10-31");
//        oldE.setEndDate("2023-11-10");
//        list.add(oldE);
//
//        TimeEntity oldE1 = new TimeEntity();
//        oldE1.setId("2");
//        oldE1.setStartDate("2023-12-20");
//        oldE1.setEndDate("2024-01-10");
//        list.add(oldE1);
//
//        TimeEntity newE = new TimeEntity();
//        newE.setId("");
//        newE.setStartDate("2023-11-01");
//        newE.setEndDate("2023-12-20");
        //场景12通过
        // |-------|
        //         |--------------------|
//        TimeEntity oldE = new TimeEntity();
//        oldE.setId("1");
//        oldE.setStartDate("2023-10-31");
//        oldE.setEndDate("2023-11-10");
//        list.add(oldE);
//
//        TimeEntity newE = new TimeEntity();
//        newE.setId("");
//        newE.setStartDate("2023-11-10");
//        newE.setEndDate("2023-12-20");

        //场景13通过
        //                   |-------|
        //         |---------|
//        TimeEntity oldE = new TimeEntity();
//        oldE.setId("1");
//        oldE.setStartDate("2023-10-31");
//        oldE.setEndDate("2023-11-10");
//        list.add(oldE);
//
//        TimeEntity newE = new TimeEntity();
//        newE.setId("");
//        newE.setStartDate("2023-10-10");
//        newE.setEndDate("2023-10-31");

        getDates(list, newE);

    }
    public static List<TimeEntity> getDates(List<TimeEntity> oldEList, TimeEntity newE) throws ParseException {

        //即将插入日期 newE和数据库表数据有交叉
        boolean b = isOverlap(oldEList,newE);
        if(!b)
        {
            System.out.println("没有交叉,直接插入:" + JSONUtil.toJsonStr(newE));
            //插入数据库

            return new ArrayList<>();
        }

        //放到list排序
        List<TimeEntity> list = new ArrayList<>();

        list.add( new TimeEntity(newE.getId(),newE.getStartDate()));
        list.add( new TimeEntity(newE.getId(),newE.getEndDate()));

        for (TimeEntity oldEntity : oldEList) {

            list.add(new TimeEntity(oldEntity.getId(),oldEntity.getStartDate()));
            list.add(new TimeEntity(oldEntity.getId(), oldEntity.getEndDate()));
        }
        //去掉重复日期
        Map<String, TimeEntity> map = list.stream()
                .collect(Collectors.toMap(
                        TimeEntity::getDateStr,
                        Function.identity(),
                        (existing, replacement) -> StringUtils.isBlank(existing.getId()) ? existing : replacement
                ));

        List<TimeEntity> filteredList = new ArrayList<>(map.values());

        // 输出满足条件的 Entity 对象
        filteredList.forEach(System.out::println);

        list.clear();
        list.addAll(filteredList);
        list.sort(Comparator.comparing(TimeEntity::getDateStr));

        System.out.println("排序后的日期点:" + list);

        String newEStartDate = newE.getStartDate();
        String newEEndDate = newE.getEndDate();

        List<TimeEntity> dateRanges = new ArrayList<>();
        for (int i = 0; i < list.size()-1 ; i++) {
            TimeEntity dateVo = new TimeEntity();
            //  end > getDateStr >= start   分段,根据新老归属,划分id
            if(list.get(i).getDateStr().compareTo(newEStartDate)>=0&&list.get(i).getDateStr().compareTo(newEEndDate)<0){
                dateVo.setId(newE.getId());
            }else{
                if(!list.get(i).getId().equals(newE.getId())){
                    dateVo.setId(list.get(i).getId());
                }
                if(!list.get(i+1).getId().equals(newE.getId())){
                    dateVo.setId(list.get(i+1).getId());
                }
            }
            dateVo.setId(list.get(i).getId());
            // list.get(i)   is  new end point   +1
            if( list.get(i).getDateStr().equals(newEEndDate)){

                //+1天
                dateVo.setStartDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,DateUtils.addDays(DateUtils.parseDate(newEEndDate), 1)));
            }else{
                dateVo.setStartDate(list.get(i).getDateStr());
            }
            //         if    list.get(i+1) is  new end point   +0
            // else -1
            if( list.size() == i+2 || list.get(i+1).getDateStr().equals(newEEndDate)){
                dateVo.setEndDate(list.get(i+1).getDateStr());
            }else{
                //-1天
                dateVo.setEndDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,DateUtils.addDays(DateUtils.parseDate(list.get(i+1).getDateStr()), -1)));
            }
            dateRanges.add(dateVo);
        }

        System.out.println("按照时间分段数据: " + dateRanges);
        //去除和即将入库开始结束日期有交叉的数据
        dateRanges.removeIf(dateVo ->  dateVo.getStartDate().compareTo(newE.getEndDate())<=0
                && newE.getStartDate().compareTo(dateVo.getEndDate())<=0);
        dateRanges.add(newE);
        dateRanges.sort(Comparator.comparing(TimeEntity::getStartDate));
        System.out.println("最终数据数据: " + dateRanges);

        //对库操作

        return dateRanges;
    }

    public static boolean isOverlap(List<TimeEntity> timeEntityList, TimeEntity newEntity) {
        return timeEntityList.stream()
                .anyMatch(entity -> {
                    return entity.getStartDate().compareTo(newEntity.getEndDate())<=0 && newEntity.getStartDate().compareTo(entity.getEndDate())<=0;
                });
    }
    @Data
    public static class TimeEntity implements Serializable {
        String id;

        private  String dateStr;

        private String startDate;
        public TimeEntity(  ){

        }



        private String endDate;
        public TimeEntity(String id,String dateStr ){
            this.id=id;
            this.dateStr =dateStr;
        }
        public TimeEntity(String id,String startDate,String endDate ){
            this.id=id;
            this.startDate =startDate;
            this.endDate = endDate;
        }



    }
}

2.针对上边也可以用泛型+发射,来写一遍。TimeEntity在这里就相当于表对应的实体类。两种都可以,就看怎么处理业务数据。


import com.xhj.framework.web.common.DateUtils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

public class GenericEntityProcessor<T> {

    public List<T> getDates(List<T> oldEList, T newE) throws ParseException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
        boolean b = isOverlap(oldEList, newE);
        if (!b) {
            System.out.println("No overlap, directly insert: " + newE.toString());
            return new ArrayList<>();
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        // Extracting fields using reflection
        Field idField = getField("id", newE.getClass());
        Field startDateField = getField("startDate", newE.getClass());
        Field endDateField = getField("endDate", newE.getClass());

        List<T> list = new ArrayList<>();
        list.add(createEntity(newE, idField, startDateField));
        list.add(createEntity(newE, idField, endDateField));

        for (T oldEntity : oldEList) {
            list.add(createEntity(oldEntity, idField, startDateField));
            list.add(createEntity(oldEntity, idField, endDateField));
        }

        // Remove duplicates based on the dateStr field
        Map<String, T> map = list.stream()
                .collect(Collectors.toMap(
                        entity -> (String) getFieldValue(entity, "dateStr"),
                        Function.identity(),
                        (existing, replacement) -> getFieldValue(existing, "id").equals("") ? existing : replacement
                ));

        List<T> filteredList = new ArrayList<>(map.values());
        filteredList.forEach(System.out::println);

        list.clear();
        list.addAll(filteredList);
        list.sort(Comparator.comparing(entity -> (String) getFieldValue(entity, "dateStr")));
        System.out.println("最终按照日期排序后的list: " + list);

        List<T> dateRanges = processDateRanges(list, newE);

        // Further processing and database operations
        return dateRanges;
    }

    public List<T> processDateRanges(List<T> list, T newE) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String newEStartDate = (String) getFieldValue(newE, "startDate");
        String newEEndDate = (String) getFieldValue(newE, "endDate");

        List<T> dateRanges = new ArrayList<>();
        for (int i = 0; i < list.size() - 1; i++) {
            T dateVo = createInstance(newE);

            String currentDateStr = (String) getFieldValue(list.get(i), "dateStr");
            String nextDateStr = (String) getFieldValue(list.get(i + 1), "dateStr");

            if (currentDateStr.compareTo(newEStartDate) >= 0 && currentDateStr.compareTo(newEEndDate) < 0) {
                setFieldValue(dateVo, "id", getFieldValue(newE, "id"));
            } else {
                if (!getFieldValue(list.get(i), "id").equals(getFieldValue(newE, "id"))) {
                    setFieldValue(dateVo, "id", getFieldValue(list.get(i), "id"));
                }
                if (!getFieldValue(list.get(i + 1), "id").equals(getFieldValue(newE, "id"))) {
                    setFieldValue(dateVo, "id", getFieldValue(list.get(i + 1), "id"));
                }
            }

            if (currentDateStr.equals(newEEndDate)) {
                //+1天
                setFieldValue(dateVo, "startDate", DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,DateUtils.addDays(DateUtils.parseDate(newEEndDate), 1)));
            } else {
                setFieldValue(dateVo, "startDate", currentDateStr);
            }

            if (list.size() == i + 2 || nextDateStr.equals(newEEndDate)) {
                setFieldValue(dateVo, "endDate", nextDateStr);
            } else {
                //-1天
                setFieldValue(dateVo, "endDate",DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,DateUtils.addDays(DateUtils.parseDate(nextDateStr), -1)));
            }

            dateRanges.add(dateVo);
        }

        System.out.println("按照时间分段数据: " + dateRanges);

        // Remove date ranges with overlap
        dateRanges.removeIf(dateVo -> {
            return ((String) getFieldValue(dateVo, "startDate")).compareTo(newEEndDate) <= 0
                    && newEStartDate.compareTo((String) getFieldValue(dateVo, "endDate")) <= 0;
        });

        dateRanges.add(newE);
        dateRanges.sort(Comparator.comparing(entity -> (String) getFieldValue(entity, "startDate")));
        return dateRanges;
    }

    public boolean isOverlap(List<T> entityList, T newEntity) throws IllegalAccessException {
        String newStartDate = (String) getFieldValue(newEntity, "startDate");
        String newEndDate = (String) getFieldValue(newEntity, "endDate");

        return entityList.stream()
                .anyMatch(entity -> {
                    return ((String) getFieldValue(entity, "startDate")).compareTo(newEndDate) <= 0 &&
                            newStartDate.compareTo((String) getFieldValue(entity, "endDate")) <= 0;
                });
    }

    private Field getField(String fieldName, Class<?> clazz) {
        try {
            return clazz.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
            return null;
        }
    }

    private Object getFieldValue(T entity, String fieldName) {
        try {
            Field field = entity.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            return field.get(entity);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
            return null;
        }
    }
    private void setFieldValue(T entity, String fieldName, Object value) {
        try {
            Field field = entity.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(entity, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private T createInstance(T entity) {
        try {
            return (T) entity.getClass().getConstructor().newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    private T createEntity(T entity, Field idField, Field dateField) throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
        Object idValue = idField.get(entity);
        Object dateValue = dateField.get(entity);

        Constructor<?> constructor = entity.getClass().getConstructor(idField.getType(), dateField.getType());
        T newEntity = (T) constructor.newInstance(idValue, dateValue);

        return newEntity;
    }

    // Example of usage
    public static void main(String[] args) throws ParseException, InvocationTargetException, IllegalAccessException, InstantiationException, NoSuchMethodException {
        List<TimeEntity> list = new ArrayList<>();
//        TimeEntity oldE = new TimeEntity();
//        oldE.setId("1");
//        oldE.setStartDate("2023-10-31");
//        oldE.setEndDate("2023-11-10");
//        list.add(oldE);

        TimeEntity oldE1 = new TimeEntity();
        oldE1.setId("2");
        oldE1.setStartDate("2024-04-20");
        oldE1.setEndDate("2024-11-10");
        list.add(oldE1);

        TimeEntity newE = new TimeEntity();
        newE.setId("");
        newE.setStartDate("2024-04-30");
        newE.setEndDate("2024-11-15");
        GenericEntityProcessor<TimeEntity> processor = new GenericEntityProcessor<>();
        List<TimeEntity> dateRanges = processor.getDates(list, newE);
        System.out.println("最终数据数据: " + dateRanges);
        // Further processing with the result
    }
}

两种写法最终实现截取时间段,联系不间断,无重叠。

最讨厌处理日期了......做个笔记记录下实现.

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值