Well, this is really a "strange" idea, but look if this "concept" is better.
Basically, the idea is to combine all overlapping dates into several “ranges” as much as possible, which means that in your first example you will get two different ranges (start date 1 to end date 2 and (start date 3 to end date 3), and in the second you get one (start date 1 to end date 4)
So, if a set has only one separate range, then you have no spaces, others are reasonable, you do.
import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.List; public class TestDateRanges { public static void main(String[] args) { try { List<Date[]> dates = new ArrayList<>( Arrays.asList( new Date[][]{ {makeDate("1.1.2015"), makeDate("5.1.2015")}, {makeDate("3.1.2015"), makeDate("10.1.2015")}, {makeDate("15.1.2015"), makeDate("20.1.2015")},} ) ); Collections.sort(dates, new Comparator<Date[]>() { @Override public int compare(Date[] o1, Date[] o2) { return o1[0].compareTo(o2[0]); } }); List<Date[]> ranges = new ArrayList<>(dates.size()); Date[] baseRange = null; for (Date[] range : dates) { if (baseRange == null) { baseRange = range; ranges.add(baseRange); } else if ((baseRange[0].before(range[0]) || baseRange[0].equals(range[0])) && (baseRange[1].after(range[0]) || baseRange[1].equals(range[0])) { System.out.println("> Overlap " + format(baseRange) + " <-> " + format(range)); if (range[1].after(baseRange[1])) { baseRange[1] = range[1]; } } else { System.out.println("> Out of range " + format(baseRange) + " >-< " + format(range)); baseRange = range; ranges.add(baseRange); } } System.out.println("Has " + ranges.size() + " distinct ranges"); for (Date[] range : ranges) { System.out.println(format(range)); } } catch (ParseException exp) { exp.printStackTrace(); } } public static final DateFormat FORMAT = new SimpleDateFormat("dMyyyy"); protected static final Date makeDate(String value) throws ParseException { return FORMAT.parse(value); } private static String format(Date[] baseRange) { return FORMAT.format(baseRange[0]) + "->" + FORMAT.format(baseRange[1]); } private static Date[] makeDateRange(String from, String to) throws ParseException { return new Date[]{makeDate(from), makeDate(to)}; } }
What exits ...
> Overlap 1.1.2015->5.1.2015 <-> 3.1.2015->10.1.2015 > Out of range 1.1.2015->10.1.2015 >-< 15.1.2015->20.1.2015 Has 2 distinct ranges 1.1.2015->10.1.2015 15.1.2015->20.1.2015
Now, if I change the set to ...
List<Date[]> dates = new ArrayList<>( Arrays.asList( new Date[][]{ {makeDate("1.1.2015"), makeDate("5.1.2015")}, {makeDate("3.1.2015"), makeDate("10.1.2015")}, {makeDate("15.1.2015"), makeDate("20.1.2015")}, makeDateRange("2.1.2015", "25.1.2015") } ) );
displays ...
> Overlap 1.1.2015->5.1.2015 <-> 2.1.2015->25.1.2015 > Overlap 1.1.2015->25.1.2015 <-> 3.1.2015->10.1.2015 > Overlap 1.1.2015->25.1.2015 <-> 15.1.2015->20.1.2015 Has 1 distinct ranges 1.1.2015->25.1.2015
This is just a conceptual idea, and you should beware that this example changes the data in the dates list, so you want to make sure that you have the first copy of the data