i have set of date ranges, i need to get the combined date range ,if any of the date overlaps in java

2.9k Views Asked by At

I have set of date ranges, I need to get the combined date range if any of the dates overlap in Java.

Given three sets of date ranges, if any of the dates overlap with another range of dates need to be combined.

Example:

20170101-20170331
20170101-20170430
20170430-20170501

Expected result is:

20170101-20170430
20170430-20170501

I have all the dates in String Variable. Can please any one help me to how to write the code for that. I have pasted below my code.

I want to achieve the expected results. I couldn't find out how I need to modify this code. I am a beginner, please help me to do that. I have got this sample program from StackOverflow.

package com.kkkkk.Combine;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;

public class Ideone {
    public static void main(String[] args) throws java.lang.Exception {
        ArrayList<Interval> x = new ArrayList<>();
        x.add(new Interval("20170430", "20170501")); // "20170101", "20170430"
        x.add(new Interval("20170101", "20170430"));// 20170101-20170430
                x.add(new Interval("20170101", "20170331"));
                x = merge(x);

        for (Interval i1 : x) {
            System.out.println(i1.getStartDate() + " " + i1.getEndDate());

        }

    }

    public static ArrayList<Interval> merge(ArrayList<Interval> intervals) {


        if (intervals.size() == 0 || intervals.size() == 1)
            return intervals;

        ArrayList<Interval> result = new ArrayList<Interval>();

        Collections.sort(intervals, new IntervalComparator());


        System.out.println("intervals ggggg\n" + intervals + "\n");

        Interval first = intervals.get(0);

        String start = first.getStartDate();
        String end = first.getEndDate();
        Date startDateF = null;
        Date endDateF = null;

        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            startDateF = sdf.parse(start);
            endDateF = sdf.parse(end);


            // ArrayList<Interval> result = new ArrayList<Interval>();

            for (int i = 1; i < intervals.size(); i++) {

                Interval current = intervals.get(i);

                Date currentEndDate = sdf.parse(current.getEndDate());
                Date currentStartDate = sdf.parse(current.getStartDate());

                // if ((current.getStartDate().after(endDateF)) ||
                                Date d1 = minDate(endDateF, currentStartDate);

                                if ((currentStartDate).compareTo(endDateF) <= 0) {
                    endDateF = maxDate(currentEndDate, endDateF);

                                                        } else {

                                                            result.add(new Interval(start, (sdf.format(endDateF))));

                    // start = current.start;
                    // end = current.end;

                    start = sdf.format(currentStartDate);
                    endDateF = (currentEndDate);



    enter code here

                }

            }
            result.add(new Interval(start, end));
            // result.add(new Interval(start, (sdf.format(endDateF))));
        }

        catch (ParseException ex) {
            ex.printStackTrace();
        }

        // result.add(new Interval(start, end));

        return result;
        // return intervals;

    }

    public static Date minDate(Date date1, Date date2) {
        // if date1 before date2 then return date1 else return date2

        return date1.before(date2) ? date1 : date2;
    }

    /**
     * find Max Dates
     * 
     * @param date1
     * @param date2
     * @return
     */
    public static Date maxDate(Date date1, Date date2) {
        // if date1 after date2 then return date1 else return date2
        System.out.println("date max");
        return date1.after(date2) ? date1 : date2;
    }
}
3

There are 3 best solutions below

0
On

I assume your Interval is something like this:

    private static class Interval {
    private String begin;
    private String end;

    public Interval(String begin, String end) {
        this.begin = begin;
        this.end = end;
    }

    public String getStartDate() {
        return begin;
    }

    public String getEndDate() {
        return end;
    }
}

What you need to do is to merge a Interval list. A solution is sort list with start date then end date. And then store the earliest start time and latest end time in a cursor variable. A example:

    public List<Interval> merge(List<Interval> intervals) {
    Collections.sort(intervals, new Comparator<Interval>() {
        @Override
        public int compare(Interval o1, Interval o2) {
            if (o1.getStartDate().equals(o2.getStartDate())) {
                return o1.getEndDate().compareTo(o2.getEndDate());
            }
            return o1.getStartDate().compareTo(o2.getStartDate());
        }
    });
    List<Interval> ret = new ArrayList<>();
    String MAX_VAL = "99999999";
    String MIN_VAL = "00000000";
    String start = MAX_VAL, end = MIN_VAL;

    for (Interval interval : intervals) {
        if (interval.getStartDate().compareTo(end) > 0) {
            if (start.compareTo(MAX_VAL) < 0) {
                ret.add(new Interval(start, end));
            }
            start = interval.getStartDate();
            end = interval.getEndDate();
        } else {
            if (start.compareTo(interval.getStartDate()) < 0) {
                start = interval.getStartDate();
            }
            if (end.compareTo(interval.getEndDate()) > 0) {
                end = interval.getEndDate();
            }
        }
    }
    if (start.compareTo(MAX_VAL) < 0) {
        ret.add(new Interval(start, end));
    }
    return ret;
}
0
On

ISO 8601

Use standard ISO 8601 formats when serializing date-time values to text. Your format complies with the “basic” version of the standard, but better to use the full format when possible:

YYYY-MM-DD

Use the standard format for a date range, using a slash character as separator:

YYYY-MM-DD/YYYY-MM-DD

If you cannot alter the input strings, split the string on the hyphen. Parse each piece as a LocalDate. Use those objects to instantiate a LocalDateRange.

LocalDate ld = LocalDate.parse( "20170101" , DateTimeFormatter.BASIC_ISO_DATE ) ; 

LocalDateRange

Use the LocalDateRange class from the ThreeTen-Extra project which extends java.time class functionality. Uses the standard format when parsing and generating text.

LocalDateRange range = LocalDateRange.parse( "2017-01-01/2017-03-31" ) ;

Collect in a List<LocalDateRange>.

To sort, write a comparator that calls LocalDateRange::getStart.

Compare to another range to see if they overlap. If so, combine with a call to union.

if ( range.overlaps( otherRange ) ) {
    range = range.union( otherRange ) ;
}

If they do not overlap, you have finished that round. Store this result in another List<LocalDateRange>. Start another round with the next range.

Lather, rinse, repeat.

0
On
public static void main(String[] args) {
    // TODO Auto-generated method stub


    ArrayList<MainLab.Interval> list = new ArrayList<MainLab.Interval>();


    list.add(new MainLab.Interval("20170430", "20170501"));
    list.add(new MainLab.Interval("20170101", "20170430"));
    list.add(new MainLab.Interval("20170101", "20170331"));



for (Iterator iterator = mergeInterval(list).iterator(); iterator.hasNext();) {
    Interval interval = (Interval) iterator.next();

    System.out.println(interval.getStart()+ "==="+interval.getEnd());
}




}

public static List<Interval>  mergeInterval(ArrayList<MainLab.Interval> list){

    /*
     * Sort the list , Interval class have implemented Comparable Interface.
     *  So we will get sorted intervals. Intervals sorted based on start of interval
     */
    Collections.sort(list);
    Set<MainLab.Interval> resultlist = new TreeSet<MainLab.Interval>();

    List<MainLab.Interval> mergedIntervals = new ArrayList<MainLab.Interval>();

    //declare date formate to parse and format date from string to and from
    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
    if(list.size() == 1){
        //resultlist = list
        return list;
    }
    if(list.size() > 1){
        // get first interval Object. conside it as first interval
        Interval mergeInterval = list.get(0);

        // loop other intervals from second in the list
        for(int i=1; i< list.size() ; i++){

            Interval interval2 = list.get(i);
            try{


                Date startDate1  = sdf.parse(mergeInterval.getStart());
                Date endDate1  = sdf.parse(mergeInterval.getEnd());



                Date startDate2  = sdf.parse(interval2.getStart());
                Date endDate2  = sdf.parse(interval2.getEnd());


                // compare if current interval's start date is before merging interval's end date
                // then the two intervals are overlaping
                if(startDate2.compareTo(endDate1) < 0 ){

                    // check whether end date of current loop interval is after the merging interval.
                    // then we need to update the end date of merging interval with looping interval's end date
                    if(endDate2.compareTo(endDate1) > 0 ){

                        mergeInterval.setEnd(interval2.getEnd());

                    }
                }else{
                    // compare if current interval's start date is after merging interval's end date
                    // then it must be a new interval start so swap mergInterval variable with  current looping interval

                     mergeInterval = interval2;

                }

                //add merge interval to set. 
                resultlist.add(mergeInterval);
            }catch(Exception ex){
                ex.printStackTrace();
            }

        }

    }
    mergedIntervals.addAll(resultlist);
    return mergedIntervals;

}

public static class Interval implements Comparable<Interval>{

    private String start;
    private String end;

    public String getStart() {
        return start;
    }
    public void setStart(String start) {
        this.start = start;
    }
    public String getEnd() {
        return end;
    }
    public void setEnd(String end) {
        this.end = end;
    }
    public Interval(){



            }
    public Interval(String start,String end){

        this.start = start;
        this.end = end;

    }
        @Override
        public boolean equals(Object obj) {
            // TODO Auto-generated method stub
            Interval inteval = (Interval)obj;
            return this.getStart().equals(inteval.getStart()) && this.getEnd().equals(inteval.getEnd()) ;
        }

    @Override
    public int compareTo(Interval o) {
        // TODO Auto-generated method stub

        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        try{
            Date startDate  = sdf.parse(start);
            Date endDate  = sdf.parse(end);
            Date pstartDate  = sdf.parse(o.start);
            Date pendDate  = sdf.parse(o.end);


            return startDate.compareTo(pstartDate);

        }catch(Exception ex){
            ex.printStackTrace();
        }
        return 0;
    }


}